From 04657d2c1da2df8ee764adedf2e9656b48046bd4 Mon Sep 17 00:00:00 2001 From: Marcel Date: Fri, 12 Sep 2014 15:23:20 +0200 Subject: [PATCH 001/205] added ToxID struct --- corestructs.h | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/corestructs.h b/corestructs.h index ebaab4534..a2bb6f31f 100644 --- a/corestructs.h +++ b/corestructs.h @@ -10,6 +10,32 @@ class QTimer; enum class Status : int {Online = 0, Away, Busy, Offline}; +#define TOX_ID_PUBLIC_KEY_LENGTH 64 +#define TOX_ID_NO_SPAM_LENGTH 8 +#define TOX_ID_CHECKSUM_LENGTH 4 + +struct ToxID +{ + QString publicKey; + QString noSpam; + QString checkSum; + + QString toString() const + { + return publicKey + noSpam + checkSum; + } + + ToxID static fromString(QString id) + { + ToxID toxID; + toxID.publicKey = id.left(TOX_ID_PUBLIC_KEY_LENGTH); + toxID.noSpam = id.mid(TOX_ID_PUBLIC_KEY_LENGTH, TOX_ID_NO_SPAM_LENGTH); + toxID.checkSum = id.right(TOX_ID_CHECKSUM_LENGTH); + return toxID; + } + +}; + struct DhtServer { QString name; From c3a8cd01f37e4b0530c3b0c1e541328d87ab9e4c Mon Sep 17 00:00:00 2001 From: Marcel Date: Fri, 12 Sep 2014 15:32:15 +0200 Subject: [PATCH 002/205] removed settingsform, removed selfcamview from widget --- qtox.pro | 2 - widget/form/settingsform.cpp | 142 ----------------------------------- widget/form/settingsform.h | 67 ----------------- widget/widget.cpp | 36 +-------- widget/widget.h | 6 -- 5 files changed, 1 insertion(+), 252 deletions(-) delete mode 100644 widget/form/settingsform.cpp delete mode 100644 widget/form/settingsform.h diff --git a/qtox.pro b/qtox.pro index 7b52d779c..4bc5bba89 100644 --- a/qtox.pro +++ b/qtox.pro @@ -79,7 +79,6 @@ win32 { HEADERS += widget/form/addfriendform.h \ widget/form/chatform.h \ widget/form/groupchatform.h \ - widget/form/settingsform.h \ widget/form/filesform.h \ widget/tool/chattextedit.h \ widget/tool/friendrequestdialog.h \ @@ -116,7 +115,6 @@ SOURCES += \ widget/form/addfriendform.cpp \ widget/form/chatform.cpp \ widget/form/groupchatform.cpp \ - widget/form/settingsform.cpp \ widget/form/filesform.cpp \ widget/tool/chattextedit.cpp \ widget/tool/friendrequestdialog.cpp \ diff --git a/widget/form/settingsform.cpp b/widget/form/settingsform.cpp deleted file mode 100644 index 3d4a213da..000000000 --- a/widget/form/settingsform.cpp +++ /dev/null @@ -1,142 +0,0 @@ -/* - Copyright (C) 2014 by Project Tox - - This file is part of qTox, a Qt-based graphical interface for Tox. - - This program 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. - 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 COPYING file for more details. -*/ - -#include "settingsform.h" -#include "widget/widget.h" -#include "settings.h" -#include "smileypack.h" -#include "ui_mainwindow.h" -#include -#include -#include -#include -#include - -SettingsForm::SettingsForm() - : QObject() -{ - main = new QWidget(), head = new QWidget(); - QFont bold, small; - bold.setBold(true); - small.setPixelSize(13); - small.setKerning(false); - headLabel.setText(tr("User Settings","\"Headline\" of the window")); - headLabel.setFont(bold); - - nameLabel.setText(tr("Name","Username/nick")); - statusTextLabel.setText(tr("Status","Status message")); - idLabel.setText("Tox ID " + tr("(click here to copy)", "Click on this text to copy TID to clipboard")); - id.setFont(small); - id.setTextInteractionFlags(Qt::TextSelectableByMouse); - id.setReadOnly(true); - id.setFrameStyle(QFrame::NoFrame); - id.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - id.setFixedHeight(id.document()->size().height()*2); - - videoTest.setText(tr("Test video","Text on a button to test the video/webcam")); - enableIPv6.setText(tr("Enable IPv6 (recommended)","Text on a checkbox to enable IPv6")); - enableIPv6.setChecked(Settings::getInstance().getEnableIPv6()); - useTranslations.setText(tr("Use translations","Text on a checkbox to enable translations")); - useTranslations.setChecked(Settings::getInstance().getUseTranslations()); - makeToxPortable.setText(tr("Make Tox portable","Text on a checkbox to make qTox a portable application")); - makeToxPortable.setChecked(Settings::getInstance().getMakeToxPortable()); - makeToxPortable.setToolTip(tr("Save settings to the working directory instead of the usual conf dir","describes makeToxPortable checkbox")); - - smileyPackLabel.setText(tr("Smiley Pack", "Text on smiley pack label")); - for (auto entry : SmileyPack::listSmileyPacks()) - smileyPackBrowser.addItem(entry.first, entry.second); - smileyPackBrowser.setCurrentIndex(smileyPackBrowser.findData(Settings::getInstance().getSmileyPack())); - - main->setLayout(&layout); - layout.addWidget(&nameLabel); - layout.addWidget(&name); - layout.addWidget(&statusTextLabel); - layout.addWidget(&statusText); - layout.addWidget(&idLabel); - layout.addWidget(&id); - layout.addWidget(&videoTest); - layout.addWidget(&enableIPv6); - layout.addWidget(&useTranslations); - layout.addWidget(&makeToxPortable); - layout.addWidget(&smileyPackLabel); - layout.addWidget(&smileyPackBrowser); - layout.addStretch(); - - head->setLayout(&headLayout); - headLayout.addWidget(&headLabel); - - connect(&videoTest, SIGNAL(clicked()), this, SLOT(onTestVideoClicked())); - connect(&enableIPv6, SIGNAL(stateChanged(int)), this, SLOT(onEnableIPv6Updated())); - connect(&useTranslations, SIGNAL(stateChanged(int)), this, SLOT(onUseTranslationUpdated())); - connect(&makeToxPortable, SIGNAL(stateChanged(int)), this, SLOT(onMakeToxPortableUpdated())); - connect(&idLabel, SIGNAL(clicked()), this, SLOT(copyIdClicked())); - connect(&smileyPackBrowser, SIGNAL(currentIndexChanged(int)), this, SLOT(onSmileyBrowserIndexChanged(int))); -} - -SettingsForm::~SettingsForm() -{ -} - -void SettingsForm::setFriendAddress(const QString& friendAddress) -{ - QString txt{friendAddress}; - txt.insert(38,'\n'); - id.setText(txt); -} - -void SettingsForm::show(Ui::MainWindow &ui) -{ - name.setText(ui.nameLabel->text()); - statusText.setText(ui.statusLabel->text()); - ui.mainContent->layout()->addWidget(main); - ui.mainHead->layout()->addWidget(head); - main->show(); - head->show(); -} - -void SettingsForm::onTestVideoClicked() -{ - Widget::getInstance()->showTestCamview(); -} - -void SettingsForm::onEnableIPv6Updated() -{ - Settings::getInstance().setEnableIPv6(enableIPv6.isChecked()); -} - -void SettingsForm::copyIdClicked() -{ - id.selectAll(); - QString txt = id.toPlainText(); - txt.replace('\n',""); - QApplication::clipboard()->setText(txt); -} - -void SettingsForm::onUseTranslationUpdated() -{ - Settings::getInstance().setUseTranslations(useTranslations.isChecked()); -} - -void SettingsForm::onMakeToxPortableUpdated() -{ - Settings::getInstance().setMakeToxPortable(makeToxPortable.isChecked()); -} - -void SettingsForm::onSmileyBrowserIndexChanged(int index) -{ - QString filename = smileyPackBrowser.itemData(index).toString(); - Settings::getInstance().setSmileyPack(filename); -} diff --git a/widget/form/settingsform.h b/widget/form/settingsform.h deleted file mode 100644 index a081d01fb..000000000 --- a/widget/form/settingsform.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - Copyright (C) 2014 by Project Tox - - This file is part of qTox, a Qt-based graphical interface for Tox. - - This program 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. - 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 COPYING file for more details. -*/ - -#ifndef SETTINGSFORM_H -#define SETTINGSFORM_H - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "widget/croppinglabel.h" - -namespace Ui {class MainWindow;} -class QString; - -class SettingsForm : public QObject -{ - Q_OBJECT -public: - SettingsForm(); - ~SettingsForm(); - - void show(Ui::MainWindow &ui); - -public slots: - void setFriendAddress(const QString& friendAddress); - -private slots: - void onTestVideoClicked(); - void onEnableIPv6Updated(); - void onUseTranslationUpdated(); - void onMakeToxPortableUpdated(); - void onSmileyBrowserIndexChanged(int index); - void copyIdClicked(); - -private: - QLabel headLabel, nameLabel, statusTextLabel, smileyPackLabel; - QTextEdit id; - CroppingLabel idLabel; - QPushButton videoTest; - QCheckBox enableIPv6, useTranslations, makeToxPortable; - QVBoxLayout layout, headLayout; - QWidget *main, *head; - QComboBox smileyPackBrowser; -public: - QLineEdit name, statusText; -}; - -#endif // SETTINGSFORM_H diff --git a/widget/widget.cpp b/widget/widget.cpp index abe14460a..532a47664 100644 --- a/widget/widget.cpp +++ b/widget/widget.cpp @@ -155,7 +155,6 @@ Widget::Widget(QWidget *parent) ui->statusButton->style()->polish(ui->statusButton); camera = new Camera; - camview = new SelfCamView(camera); // Disable some widgets until we're connected to the DHT ui->statusButton->setEnabled(false); @@ -179,7 +178,6 @@ Widget::Widget(QWidget *parent) connect(core, &Core::statusSet, this, &Widget::onStatusSet); connect(core, &Core::usernameSet, this, &Widget::setUsername); connect(core, &Core::statusMessageSet, this, &Widget::setStatusMessage); - connect(core, &Core::friendAddressGenerated, &settingsForm, &SettingsForm::setFriendAddress); connect(core, SIGNAL(fileDownloadFinished(const QString&)), &filesForm, SLOT(onFileDownloadComplete(const QString&))); connect(core, SIGNAL(fileUploadFinished(const QString&)), &filesForm, SLOT(onFileUploadComplete(const QString&))); connect(core, &Core::friendAdded, this, &Widget::addFriend); @@ -210,8 +208,6 @@ Widget::Widget(QWidget *parent) connect(setStatusOnline, SIGNAL(triggered()), this, SLOT(setStatusOnline())); connect(setStatusAway, SIGNAL(triggered()), this, SLOT(setStatusAway())); connect(setStatusBusy, SIGNAL(triggered()), this, SLOT(setStatusBusy())); - connect(&settingsForm.name, SIGNAL(editingFinished()), this, SLOT(onUsernameChanged())); - connect(&settingsForm.statusText, SIGNAL(editingFinished()), this, SLOT(onStatusMessageChanged())); connect(&friendForm, SIGNAL(friendRequested(QString,QString)), this, SIGNAL(friendRequested(QString,QString))); coreThread->start(); @@ -228,7 +224,6 @@ Widget::~Widget() if (!coreThread->isFinished()) coreThread->terminate(); delete core; - delete camview; hideMainForms(); @@ -338,9 +333,7 @@ void Widget::onTransferClicked() void Widget::onSettingsClicked() { - hideMainForms(); - settingsForm.show(*ui); - activeChatroomWidget = nullptr; + } void Widget::hideMainForms() @@ -357,20 +350,10 @@ void Widget::hideMainForms() } } -void Widget::onUsernameChanged() -{ - const QString newUsername = settingsForm.name.text(); - ui->nameLabel->setText(newUsername); - ui->nameLabel->setToolTip(newUsername); // for overlength names - settingsForm.name.setText(newUsername); - core->setUsername(newUsername); -} - void Widget::onUsernameChanged(const QString& newUsername, const QString& oldUsername) { ui->nameLabel->setText(oldUsername); // restore old username until Core tells us to set it ui->nameLabel->setToolTip(oldUsername); // for overlength names - settingsForm.name.setText(oldUsername); core->setUsername(newUsername); } @@ -378,23 +361,12 @@ void Widget::setUsername(const QString& username) { ui->nameLabel->setText(username); ui->nameLabel->setToolTip(username); // for overlength names - settingsForm.name.setText(username); -} - -void Widget::onStatusMessageChanged() -{ - const QString newStatusMessage = settingsForm.statusText.text(); - ui->statusLabel->setText(newStatusMessage); - ui->statusLabel->setToolTip(newStatusMessage); // for overlength messsages - settingsForm.statusText.setText(newStatusMessage); - core->setStatusMessage(newStatusMessage); } void Widget::onStatusMessageChanged(const QString& newStatusMessage, const QString& oldStatusMessage) { ui->statusLabel->setText(oldStatusMessage); // restore old status message until Core tells us to set it ui->statusLabel->setToolTip(oldStatusMessage); // for overlength messsages - settingsForm.statusText.setText(oldStatusMessage); core->setStatusMessage(newStatusMessage); } @@ -402,7 +374,6 @@ void Widget::setStatusMessage(const QString &statusMessage) { ui->statusLabel->setText(statusMessage); ui->statusLabel->setToolTip(statusMessage); // for overlength messsages - settingsForm.statusText.setText(statusMessage); } void Widget::addFriend(int friendId, const QString &userId) @@ -677,11 +648,6 @@ Group *Widget::createGroup(int groupId) return newgroup; } -void Widget::showTestCamview() -{ - camview->show(); -} - void Widget::onEmptyGroupCreated(int groupId) { createGroup(groupId); diff --git a/widget/widget.h b/widget/widget.h index 1fbecb412..653d72f1f 100644 --- a/widget/widget.h +++ b/widget/widget.h @@ -19,7 +19,6 @@ #include #include "widget/form/addfriendform.h" -#include "widget/form/settingsform.h" #include "widget/form/filesform.h" #include "corestructs.h" @@ -54,7 +53,6 @@ public: QThread* getCoreThread(); Camera* getCamera(); static Widget* getInstance(); - void showTestCamview(); void newMessageAlert(); bool isFriendWidgetCurActiveWidget(Friend* f); bool getIsWindowMinimized(); @@ -83,8 +81,6 @@ private slots: void onFailedToStartCore(); void onUsernameChanged(const QString& newUsername, const QString& oldUsername); void onStatusMessageChanged(const QString& newStatusMessage, const QString& oldStatusMessage); - void onUsernameChanged(); - void onStatusMessageChanged(); void setUsername(const QString& username); void setStatusMessage(const QString &statusMessage); void addFriend(int friendId, const QString& userId); @@ -137,12 +133,10 @@ private: Core* core; QThread* coreThread; AddFriendForm friendForm; - SettingsForm settingsForm; FilesForm filesForm; static Widget* instance; GenericChatroomWidget* activeChatroomWidget; FriendListWidget* contactListWidget; - SelfCamView* camview; Camera* camera; bool notify(QObject *receiver, QEvent *event); bool eventFilter(QObject *, QEvent *event); From 28e8406be9aaad2e3fd523ce356d95b0e5b34f71 Mon Sep 17 00:00:00 2001 From: Marcel Date: Fri, 12 Sep 2014 15:41:41 +0200 Subject: [PATCH 003/205] added settingsdialog --- core.cpp | 5 +- core.h | 2 +- qtox.pro | 6 +- widget/form/addfriendform.cpp | 2 +- widget/settingsdialog.cpp | 355 ++++++++++++++++++++++++++++++++++ widget/settingsdialog.h | 64 ++++++ 6 files changed, 427 insertions(+), 7 deletions(-) create mode 100644 widget/settingsdialog.cpp create mode 100644 widget/settingsdialog.h diff --git a/core.cpp b/core.cpp index 876301a63..fe1e3187b 100644 --- a/core.cpp +++ b/core.cpp @@ -718,12 +718,11 @@ void Core::setUsername(const QString& username) } } -QString Core::getSelfId() +ToxID Core::getSelfId() { uint8_t friendAddress[TOX_FRIEND_ADDRESS_SIZE]; tox_get_address(tox, friendAddress); - - return CFriendAddress::toString(friendAddress); + return ToxID::fromString(CFriendAddress::toString(friendAddress)); } QString Core::getStatusMessage() diff --git a/core.h b/core.h index 96ab86d2d..13d051017 100644 --- a/core.h +++ b/core.h @@ -49,7 +49,7 @@ public: QString getUsername(); QString getStatusMessage(); - QString getSelfId(); + ToxID getSelfId(); void increaseVideoBusyness(); void decreaseVideoBusyness(); diff --git a/qtox.pro b/qtox.pro index 4bc5bba89..96e609c33 100644 --- a/qtox.pro +++ b/qtox.pro @@ -109,7 +109,8 @@ HEADERS += widget/form/addfriendform.h \ filetransferinstance.h \ corestructs.h \ coredefines.h \ - coreav.h + coreav.h \ + widget/settingsdialog.h SOURCES += \ widget/form/addfriendform.cpp \ @@ -145,4 +146,5 @@ SOURCES += \ widget/tool/chataction.cpp \ widget/chatareawidget.cpp \ filetransferinstance.cpp \ - corestructs.cpp + corestructs.cpp \ + widget/settingsdialog.cpp diff --git a/widget/form/addfriendform.cpp b/widget/form/addfriendform.cpp index 3a44ae672..2c9b197b2 100644 --- a/widget/form/addfriendform.cpp +++ b/widget/form/addfriendform.cpp @@ -95,7 +95,7 @@ void AddFriendForm::onSendTriggered() if (id.isEmpty()) { showWarning(tr("Please fill in a valid Tox ID","Tox ID of the friend you're sending a friend request to")); } else if (isToxId(id)) { - if (id.toUpper() == Core::getInstance()->getSelfId().toUpper()) + if (id.toUpper() == Core::getInstance()->getSelfId().toString().toUpper()) showWarning(tr("You can't add yourself as a friend !","When trying to add your own Tox ID as friend")); else emit friendRequested(id, getMessage()); diff --git a/widget/settingsdialog.cpp b/widget/settingsdialog.cpp new file mode 100644 index 000000000..09cb765c1 --- /dev/null +++ b/widget/settingsdialog.cpp @@ -0,0 +1,355 @@ +#include "settingsdialog.h" +#include "settings.h" +#include "widget.h" +#include "camera.h" +#include "selfcamview.h" +#include "core.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +// ======================================= +// settings pages +//======================================== +class GeneralPage : public QWidget +{ +public: + GeneralPage(QWidget *parent = 0) : + QWidget(parent) + { + QGroupBox *group = new QGroupBox(tr("General Settings"), this); + + enableIPv6 = new QCheckBox(this); + enableIPv6->setText(tr("Enable IPv6 (recommended)","Text on a checkbox to enable IPv6")); + useTranslations = new QCheckBox(this); + useTranslations->setText(tr("Use translations","Text on a checkbox to enable translations")); + makeToxPortable = new QCheckBox(this); + makeToxPortable->setText(tr("Make Tox portable","Text on a checkbox to make qTox a portable application")); + makeToxPortable->setToolTip(tr("Save settings to the working directory instead of the usual conf dir","describes makeToxPortable checkbox")); + + QVBoxLayout *vLayout = new QVBoxLayout(); + vLayout->addWidget(enableIPv6); + vLayout->addWidget(useTranslations); + vLayout->addWidget(makeToxPortable); + group->setLayout(vLayout); + + QVBoxLayout *mainLayout = new QVBoxLayout(); + mainLayout->addWidget(group); + mainLayout->addStretch(1); + setLayout(mainLayout); + } + + QCheckBox* enableIPv6; + QCheckBox* useTranslations; + QCheckBox* makeToxPortable; +}; + +class IdentityPage : public QWidget +{ +public: + IdentityPage(QWidget* parent = 0) : + QWidget(parent) + { + // public + QGroupBox *publicGroup = new QGroupBox(tr("Public Information"), this); + QLabel* userNameLabel = new QLabel(tr("Name","Username/nick"), this); + userName = new QLineEdit(this); + QLabel* statusMessageLabel = new QLabel(tr("Status","Status message"), this); + statusMessage = new QLineEdit(this); + QVBoxLayout *vLayout = new QVBoxLayout(); + vLayout->addWidget(userNameLabel); + vLayout->addWidget(userName); + vLayout->addWidget(statusMessageLabel); + vLayout->addWidget(statusMessage); + publicGroup->setLayout(vLayout); + + // tox + QGroupBox* toxGroup = new QGroupBox(tr("Tox ID"), this); + QLabel* toxIdLabel = new QLabel(tr("Your Tox ID"), this); + toxID = new QLineEdit(this); + toxID->setReadOnly(true); + QVBoxLayout* toxLayout = new QVBoxLayout(); + toxLayout->addWidget(toxIdLabel); + toxLayout->addWidget(toxID); + toxGroup->setLayout(toxLayout); + + QVBoxLayout *mainLayout = new QVBoxLayout(); + mainLayout->setSpacing(30); + mainLayout->addWidget(publicGroup); + mainLayout->addWidget(toxGroup); + mainLayout->addStretch(1); + setLayout(mainLayout); + } + + QLineEdit* userName; + QLineEdit* statusMessage; + QLineEdit* toxID; +}; + +class PrivacyPage : public QWidget +{ +public: + PrivacyPage(QWidget* parent = 0) : + QWidget(parent) + {} +}; + +class AVPage : public QWidget +{ + Q_OBJECT +public: + AVPage(SettingsDialog* parent = 0) : + QWidget(parent) + { + QGroupBox *group = new QGroupBox(tr("Video Settings"), this); + + camView = new SelfCamView(Camera::getInstance()); + camView->hide(); // hide by default + testVideo = new QPushButton("enable video"); + connect(testVideo, SIGNAL(clicked()), this, SLOT(onTestVideoPressed())); + + QVBoxLayout *vLayout = new QVBoxLayout(); + vLayout->addWidget(testVideo); + vLayout->addWidget(camView); + group->setLayout(vLayout); + + QVBoxLayout *mainLayout = new QVBoxLayout(); + mainLayout->addWidget(group); + mainLayout->addStretch(1); + setLayout(mainLayout); + } + + ~AVPage() + { + delete camView; + } + + void showTestVideo() + { + testVideo->setText("disable video"); + camView->show(); + } + + void closeTestVideo() + { + testVideo->setText("enable video"); + camView->close(); + } + + QPushButton* testVideo; + SelfCamView* camView; + +public slots: + void onTestVideoPressed() + { + if (camView->isVisible()) { + closeTestVideo(); + } else { + showTestVideo(); + } + } +}; + +// allows Q_OBJECT macro inside cpp +#include "settingsdialog.moc" + + + +// ======================================= +// settings dialog +//======================================== +SettingsDialog::SettingsDialog(Widget *parent) : + QDialog(parent), + widget(parent) +{ + createPages(); + createButtons(); + createConnections(); + createLayout(); + setWindowTitle(tr("Settings Dialog")); +} + +void SettingsDialog::createPages() +{ + generalPage = new GeneralPage(this); + identityPage = new IdentityPage(this); + privacyPage = new PrivacyPage(this); + avPage = new AVPage(this); + + contentsWidget = new QListWidget; + contentsWidget->setViewMode(QListView::IconMode); + contentsWidget->setIconSize(QSize(100, 73)); + contentsWidget->setMovement(QListView::Static); + contentsWidget->setMaximumWidth(110); + contentsWidget->setMinimumWidth(110); + contentsWidget->setSpacing(0); + contentsWidget->setFlow(QListView::TopToBottom); + + pagesWidget = new QStackedWidget; + pagesWidget->addWidget(generalPage); + pagesWidget->addWidget(identityPage); + pagesWidget->addWidget(privacyPage); + pagesWidget->addWidget(avPage); + + QListWidgetItem *generalButton = new QListWidgetItem(contentsWidget); + generalButton->setIcon(QIcon(":/img/settings/general.png")); + generalButton->setText(tr("General")); + generalButton->setTextAlignment(Qt::AlignHCenter); + generalButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + + QListWidgetItem *identity = new QListWidgetItem(contentsWidget); + identity->setIcon(QIcon(":/img/settings/identity.png")); + identity->setText(tr("Identity")); + identity->setTextAlignment(Qt::AlignHCenter); + identity->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + + QListWidgetItem *privacy = new QListWidgetItem(contentsWidget); + privacy->setIcon(QIcon(":/img/settings/privacy.png")); + privacy->setText(tr("Privacy")); + privacy->setTextAlignment(Qt::AlignHCenter); + privacy->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + + QListWidgetItem *av = new QListWidgetItem(contentsWidget); + av->setIcon(QIcon(":/img/settings/av.png")); + av->setText(tr("Audio/Video")); + av->setTextAlignment(Qt::AlignHCenter); + av->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + + contentsWidget->setCurrentRow(0); +} + +void SettingsDialog::createButtons() +{ + okButton = new QPushButton(tr("Ok"), this); + cancelButton = new QPushButton(tr("Cancel"), this); + applyButton = new QPushButton(tr("Apply"), this); +} + +void SettingsDialog::createConnections() +{ + connect(okButton, SIGNAL(clicked()), this, SLOT(okPressed())); + connect(cancelButton, SIGNAL(clicked()), this, SLOT(close())); + connect(applyButton, SIGNAL(clicked()), this, SLOT(applyPressed())); + connect( + contentsWidget, + SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), + this, + SLOT(changePage(QListWidgetItem*,QListWidgetItem*)) + ); +} + +void SettingsDialog::createLayout() +{ + setMinimumSize(800, 500); + + QHBoxLayout *buttonsLayout = new QHBoxLayout(); + buttonsLayout->addStretch(1); + buttonsLayout->addWidget(okButton); + buttonsLayout->addWidget(cancelButton); + buttonsLayout->addWidget(applyButton); + + QHBoxLayout *hLayout = new QHBoxLayout(); + hLayout->addWidget(contentsWidget); + hLayout->addWidget(pagesWidget, 1); + + QVBoxLayout *mainLayout = new QVBoxLayout(); + mainLayout->addLayout(hLayout); + mainLayout->addLayout(buttonsLayout); + setLayout(mainLayout); +} + +void SettingsDialog::changePage(QListWidgetItem *current, QListWidgetItem *previous) +{ + if (!current) { + current = previous; + } + pagesWidget->setCurrentIndex(contentsWidget->row(current)); +} + +void SettingsDialog::okPressed() +{ + writeConfig(); + close(); +} + +void SettingsDialog::cancelPressed() +{ + close(); +} + +void SettingsDialog::applyPressed() +{ + writeConfig(); +} + +void SettingsDialog::readConfig() +{ + Settings& settings = Settings::getInstance(); + Core* core = widget->getCore(); + + generalPage->enableIPv6->setChecked(settings.getEnableIPv6()); + generalPage->useTranslations->setChecked(settings.getUseTranslations()); + generalPage->makeToxPortable->setChecked(settings.getMakeToxPortable()); + + identityPage->userName->setText(core->getUsername()); + identityPage->statusMessage->setText(core->getStatusMessage()); + identityPage->toxID->setText(core->getSelfId().toString()); +} + +void SettingsDialog::writeConfig() +{ + Settings& settings = Settings::getInstance(); + Core* core = widget->getCore(); + + + // only save settings if something changed + bool saveSettings = false; + if (settings.getEnableIPv6() != generalPage->enableIPv6->isChecked()) { + settings.setEnableIPv6(generalPage->enableIPv6->isChecked()); + saveSettings = true; + } + + if (settings.getUseTranslations() != generalPage->useTranslations->isChecked()) { + settings.setUseTranslations(generalPage->useTranslations->isChecked()); + saveSettings = true; + } + + if (settings.getMakeToxPortable() != generalPage->makeToxPortable->isChecked()) { + settings.setMakeToxPortable(generalPage->makeToxPortable->isChecked()); + saveSettings = true; + } + + if (saveSettings) { + settings.save(); + } + + + // changing core settings will automatically save them + QString userName = identityPage->userName->text(); + if (core->getUsername() != userName) { + core->setUsername(userName); + } + + QString statusMessage = identityPage->statusMessage->text(); + if (core->getStatusMessage() != statusMessage) { + core->setStatusMessage(statusMessage); + } +} + +Widget* SettingsDialog::getWidget() +{ + return widget; +} + +void SettingsDialog::closeEvent(QCloseEvent* e){ + avPage->closeTestVideo(); + QDialog::closeEvent(e); +} diff --git a/widget/settingsdialog.h b/widget/settingsdialog.h new file mode 100644 index 000000000..55575b447 --- /dev/null +++ b/widget/settingsdialog.h @@ -0,0 +1,64 @@ +#ifndef SETTINGSDIALOG_H +#define SETTINGSDIALOG_H + +#include +#include + +class Widget; +class SelfCamView; +class Camera; +class GeneralPage; +class IdentityPage; +class PrivacyPage; +class AVPage; + +class QListWidget; +class QListWidgetItem; +class QStackedWidget; +class QPushButton; +class QCheckBox; +class QLineEdit; + +// ======================================= +// settings dialog +//======================================== +class SettingsDialog : public QDialog +{ + Q_OBJECT +public: + explicit SettingsDialog(Widget *parent); + + void readConfig(); + void writeConfig(); + Widget* getWidget(); + void closeEvent(QCloseEvent *); + +public slots: + void changePage(QListWidgetItem *current, QListWidgetItem *previous); + void okPressed(); + void cancelPressed(); + void applyPressed(); + +private: + void createPages(); + void createButtons(); + void createConnections(); + void createLayout(); + + Widget* widget; + + // pages + GeneralPage* generalPage; + IdentityPage* identityPage; + PrivacyPage* privacyPage; + AVPage* avPage; + QListWidget* contentsWidget; + QStackedWidget* pagesWidget; + + // buttons + QPushButton* okButton; + QPushButton* cancelButton; + QPushButton* applyButton; +}; + +#endif // SETTINGSDIALOG_H From 4e5d1c170b2aa4b2f02986c8ac7fe8fc7dead950 Mon Sep 17 00:00:00 2001 From: Marcel Date: Fri, 12 Sep 2014 15:45:02 +0200 Subject: [PATCH 004/205] do not use getInstance of camera --- widget/settingsdialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/widget/settingsdialog.cpp b/widget/settingsdialog.cpp index 09cb765c1..0f11ee67c 100644 --- a/widget/settingsdialog.cpp +++ b/widget/settingsdialog.cpp @@ -111,7 +111,7 @@ public: { QGroupBox *group = new QGroupBox(tr("Video Settings"), this); - camView = new SelfCamView(Camera::getInstance()); + camView = new SelfCamView(parent->getWidget()->getCamera()); camView->hide(); // hide by default testVideo = new QPushButton("enable video"); connect(testVideo, SIGNAL(clicked()), this, SLOT(onTestVideoPressed())); From 1b2855e05be699e123f9b220e93207085bf6bfbc Mon Sep 17 00:00:00 2001 From: Marcel Date: Fri, 12 Sep 2014 15:46:34 +0200 Subject: [PATCH 005/205] use settings dialog in widget --- widget/widget.cpp | 5 ++++- widget/widget.h | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/widget/widget.cpp b/widget/widget.cpp index 532a47664..36b2c33c1 100644 --- a/widget/widget.cpp +++ b/widget/widget.cpp @@ -31,6 +31,7 @@ #include "widget/friendlistwidget.h" #include "camera.h" #include "widget/form/chatform.h" +#include "widget/settingsdialog.h" #include #include #include @@ -155,6 +156,7 @@ Widget::Widget(QWidget *parent) ui->statusButton->style()->polish(ui->statusButton); camera = new Camera; + settingsDialog = new SettingsDialog(this); // Disable some widgets until we're connected to the DHT ui->statusButton->setEnabled(false); @@ -333,7 +335,8 @@ void Widget::onTransferClicked() void Widget::onSettingsClicked() { - + settingsDialog->readConfig(); + settingsDialog->show(); } void Widget::hideMainForms() diff --git a/widget/widget.h b/widget/widget.h index 653d72f1f..035ea2ae0 100644 --- a/widget/widget.h +++ b/widget/widget.h @@ -37,6 +37,7 @@ class QMenu; class Core; class Camera; class FriendListWidget; +class SettingsDialog; class Widget : public QMainWindow { @@ -134,6 +135,7 @@ private: QThread* coreThread; AddFriendForm friendForm; FilesForm filesForm; + SettingsDialog* settingsDialog; static Widget* instance; GenericChatroomWidget* activeChatroomWidget; FriendListWidget* contactListWidget; From f3ecf4fa0f39b5b80e55b176a6c8e3f4fc5ad4e5 Mon Sep 17 00:00:00 2001 From: Marcel Date: Fri, 12 Sep 2014 15:50:39 +0200 Subject: [PATCH 006/205] added images --- img/settings/av.png | Bin 0 -> 6360 bytes img/settings/general.png | Bin 0 -> 2902 bytes img/settings/identity.png | Bin 0 -> 4771 bytes img/settings/privacy.png | Bin 0 -> 1883 bytes res.qrc | 4 ++++ 5 files changed, 4 insertions(+) create mode 100644 img/settings/av.png create mode 100644 img/settings/general.png create mode 100644 img/settings/identity.png create mode 100644 img/settings/privacy.png diff --git a/img/settings/av.png b/img/settings/av.png new file mode 100644 index 0000000000000000000000000000000000000000..f96f88ea84299b2428780a15d29ae37db6601c90 GIT binary patch literal 6360 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 A^8f$< literal 0 HcmV?d00001 diff --git a/img/settings/identity.png b/img/settings/identity.png new file mode 100644 index 0000000000000000000000000000000000000000..806bb525efc2ea73d087891152331199cf543f99 GIT binary patch literal 4771 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 literal 0 HcmV?d00001 diff --git a/img/settings/privacy.png b/img/settings/privacy.png new file mode 100644 index 0000000000000000000000000000000000000000..763478290b8b0592c3f155013ad7d4f4637608d1 GIT binary patch literal 1883 zcmV-h2c-CkP)gtR(J>n?~InQFIz8Zp$*KF3uN*QzsEcO+*L2 zVsvxPDEeXVbMj$R=K|s@i$dni#++G1%<$~a5JaK4vQi3dub1wFHSvXNOYd!Z;rzd~ z_c_mVpZ@N1&ON8+UVw^xFDhcjDpmk^#SmvO+S+WVD3HKm zYy_}Q!Vu#PaR#rg%~nmvkf+0#0pRr0&Mhh`sv|Km@lVrWQGR+?hrBca%_03oNgM|SAEX#HuJalk>baeC`KPCyj*q}fjR))U=>FMdE zNl8gvy>*3}54JLMf2cq_OCnyMlD0hP@mC6-l?0yZT zM>!mhp=VB?87zjc&aTdZk)ChF1L1jIyX&J}3wfRoxk@@59R>;{M0vel#jRVnUf5W) zaZ)ILTrQW=X0s(zARn((jj^>8+2_L!~1HL5QY6M3UR>)-PMStf;1@Cbl>2 zD~?yB$steK00DsZ_V(fLE_(Ol{8jl=?RNWsK-<;S)Wp`;*Qd)N$4FXS3~FbHN~N+7 z89L-z{Gj+I(_oWz?6|QvoE=V;Uaxo0nLDT9LED*GGvB{ne|_qc{1J{Q`V|m!irD~Q z1%TH8j0B*QB2Gp|#;5!C@B8Wg=MC#OOgehx=&Ih_aRc}pKskUC!jXUbOqXR&F~1Ig z1F#9e^HRZ3C=}gu-=2H<{^!k`Hjh8{!?6{;bf@#3>m~r4F9-Qoh%b>J!x1a_+2jjn z&Ys!pa5$KyOP0?1F;c@|7{;^vlih2ps;bPD zXDeqpoz5Xr+*bfdAso3QS0LK}6o#YJS(g1z5QHe6=d}`tDkdB$lIs`}mVVba6MrTQ zFeJ}OY9OP~_atdf10+6qNtd;wqN1Gf@$vQAf!a2uQYmyeI$~Q|T1HD;DQYC;QMZQpiYr_(*OTg2gTFhw5}rB_x~z7wV{Ojd)s=+9+DM@P5q*tuhqCChUANp>es zoE);gVEvY^uC7?I&q2yry;5cukT-8--ma&?002vt<#yi6yj{NegKQ)#AS04TT+CUV zLjtwWS)4;gB#*dAfk>pZw6qK1XhVSnsEHFNHin}O1rnfQV`JUnXhVSnsLPix$A_a0 z1rngnojW%!9Bn9&09AXXc1G=$T3rzKy4owXGbj*=#Phs1cX@7JApfV^?e+n=%X9PO zHd~k5#1PHR&0{Q?mcr_)YNJ1!>Z)p^CDT&a+}u1yZu!X$2mrKNTSsr*vNgM|uI{n! ztFEq2w{^?b>{e^*XgTI4yS1#ixVY>2tMfm5bZ5z<`u@A`llFYFXNk>b6MeZ{%C#(6 z0ZD!~`NH8NhY#rW`n!SH+wJxNv)`JXd*h!QFUtjpY`QFy$#k`>ysRWp7yzKx>+hD8 zmz9`IrmJ)e5m5}oxQn+JAL#8vpT*mY4=@blra(keYHI5F$x|lxdZ)+aDU4WWrS7uI`{1}+E@vQn0d({s7#+Tx literal 0 HcmV?d00001 diff --git a/res.qrc b/res.qrc index cbf038a58..6a121b0ad 100644 --- a/res.qrc +++ b/res.qrc @@ -135,5 +135,9 @@ ui/fileTransferInstance/emptyRGreenFileButton.png ui/fileTransferInstance/emptyRRedFileButton.png audio/notification.pcm + img/settings/general.png + img/settings/identity.png + img/settings/privacy.png + img/settings/av.png From 7e7cebf6b62f657f180d12ff87d573f90a1ea3b3 Mon Sep 17 00:00:00 2001 From: krepa098 Date: Fri, 12 Sep 2014 19:09:05 +0200 Subject: [PATCH 007/205] added smiley selection to the new settings dialog, new default search- --- smileypack.cpp | 36 +++++++++++++++++++++++++----------- smileypack.h | 9 ++++++--- widget/settingsdialog.cpp | 23 +++++++++++++++++++++++ 3 files changed, 54 insertions(+), 14 deletions(-) diff --git a/smileypack.cpp b/smileypack.cpp index 5af07194f..57a754c76 100644 --- a/smileypack.cpp +++ b/smileypack.cpp @@ -40,24 +40,38 @@ SmileyPack& SmileyPack::getInstance() return smileyPack; } -QList > SmileyPack::listSmileyPacks(const QString &path) +QList > SmileyPack::listSmileyPacks(const QStringList &paths) { QList > smileyPacks; - QDir dir(path); - foreach (const QString& subdirectory, dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) + for (QString path : paths) { - dir.cd(subdirectory); + if (path.leftRef(1) == "~") + path.replace(0, 1, QDir::homePath()); - QFileInfoList entries = dir.entryInfoList(QStringList() << "emoticons.xml", QDir::Files); - if (entries.size() > 0) // does it contain a file called emoticons.xml? + QDir dir(path); + if (!dir.exists()) + continue; + + for (const QString& subdirectory : dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) { - QString packageName = dir.dirName(); - QString relPath = QDir(QCoreApplication::applicationDirPath()).relativeFilePath(entries[0].absoluteFilePath()); - smileyPacks << QPair(packageName, relPath); - } + dir.cd(subdirectory); - dir.cdUp(); + QFileInfoList entries = dir.entryInfoList(QStringList() << "emoticons.xml", QDir::Files); + if (entries.size() > 0) // does it contain a file called emoticons.xml? + { + QString packageName = dir.dirName(); + QString absPath = entries[0].absoluteFilePath(); + QString relPath = QDir(QCoreApplication::applicationDirPath()).relativeFilePath(absPath); + + if (relPath.leftRef(2) == "..") + smileyPacks << QPair(packageName, absPath); + else + smileyPacks << QPair(packageName, relPath); // use relative path for subdirectories + } + + dir.cdUp(); + } } return smileyPacks; diff --git a/smileypack.h b/smileypack.h index 9f4ea31ba..1d4c9ef30 100644 --- a/smileypack.h +++ b/smileypack.h @@ -22,7 +22,10 @@ #include #include -#define SMILEYPACK_DEFAULT_PATH "./smileys" +#define SMILEYPACK_SEARCH_PATHS \ + { \ + "./smileys", "/usr/share/qtox/smileys", "/usr/share/emoticons", "~/.kde4/share/emoticons", "~/.kde/share/emoticons" \ + } //maps emoticons to smileys class SmileyPack : public QObject @@ -30,10 +33,10 @@ class SmileyPack : public QObject Q_OBJECT public: static SmileyPack& getInstance(); - static QList> listSmileyPacks(const QString& path = SMILEYPACK_DEFAULT_PATH); + static QList > listSmileyPacks(const QStringList& paths = SMILEYPACK_SEARCH_PATHS); static bool isValid(const QString& filename); - bool load(const QString &filename); + bool load(const QString& filename); QString smileyfied(QString msg); QList getEmoticons() const; QString getAsRichText(const QString& key); diff --git a/widget/settingsdialog.cpp b/widget/settingsdialog.cpp index 0f11ee67c..4f9c26a9b 100644 --- a/widget/settingsdialog.cpp +++ b/widget/settingsdialog.cpp @@ -4,6 +4,7 @@ #include "camera.h" #include "selfcamview.h" #include "core.h" +#include "smileypack.h" #include #include @@ -14,6 +15,7 @@ #include #include #include +#include // ======================================= @@ -41,8 +43,23 @@ public: vLayout->addWidget(makeToxPortable); group->setLayout(vLayout); + // theme + QGroupBox* themeGroup = new QGroupBox(tr("Theme")); + QLabel* smileyLabel = new QLabel(tr("Smiley Pack")); + smileyPack = new QComboBox(this); + + auto smileyPacks = SmileyPack::listSmileyPacks(); + for(auto pack : smileyPacks) + smileyPack->addItem(QString("%1 (%2)").arg(pack.first).arg(pack.second), pack.second); + + QVBoxLayout* themeLayout = new QVBoxLayout(); + themeLayout->addWidget(smileyLabel); + themeLayout->addWidget(smileyPack); + themeGroup->setLayout(themeLayout); + QVBoxLayout *mainLayout = new QVBoxLayout(); mainLayout->addWidget(group); + mainLayout->addWidget(themeGroup); mainLayout->addStretch(1); setLayout(mainLayout); } @@ -50,6 +67,7 @@ public: QCheckBox* enableIPv6; QCheckBox* useTranslations; QCheckBox* makeToxPortable; + QComboBox* smileyPack; }; class IdentityPage : public QWidget @@ -327,6 +345,11 @@ void SettingsDialog::writeConfig() saveSettings = true; } + if (settings.getSmileyPack() != generalPage->smileyPack->currentData().toString()) { + settings.setSmileyPack(generalPage->smileyPack->currentData().toString()); + saveSettings = true; + } + if (saveSettings) { settings.save(); } From 968b46a86bfaa3b1ed86405be45d8af9a81d6bf8 Mon Sep 17 00:00:00 2001 From: apprb Date: Sat, 13 Sep 2014 01:54:03 +0700 Subject: [PATCH 008/205] get rid of .setBlockFormat(..) in ChatAreaWidget::insertMessage(..) function --- widget/chatareawidget.cpp | 12 ++++++------ widget/tool/chataction.cpp | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/widget/chatareawidget.cpp b/widget/chatareawidget.cpp index 203633386..199420e9f 100644 --- a/widget/chatareawidget.cpp +++ b/widget/chatareawidget.cpp @@ -44,10 +44,10 @@ ChatAreaWidget::ChatAreaWidget(QWidget *parent) : chatTextTable->format().setCellSpacing(2); chatTextTable->format().setWidth(QTextLength(QTextLength::PercentageLength,100)); - nameFormat.setAlignment(Qt::AlignRight); - nameFormat.setNonBreakableLines(true); - dateFormat.setAlignment(Qt::AlignLeft); - dateFormat.setNonBreakableLines(true); +// nameFormat.setAlignment(Qt::AlignRight); +// nameFormat.setNonBreakableLines(true); +// dateFormat.setAlignment(Qt::AlignLeft); +// dateFormat.setNonBreakableLines(true); connect(this, &ChatAreaWidget::anchorClicked, this, &ChatAreaWidget::onAnchorClicked); connect(verticalScrollBar(), SIGNAL(rangeChanged(int,int)), this, SLOT(onSliderRangeChanged())); @@ -104,8 +104,8 @@ void ChatAreaWidget::insertMessage(ChatAction *msgAction) checkSlider(); int row = chatTextTable->rows() - 1; - chatTextTable->cellAt(row,0).firstCursorPosition().setBlockFormat(nameFormat); - chatTextTable->cellAt(row,2).firstCursorPosition().setBlockFormat(dateFormat); +// chatTextTable->cellAt(row,0).firstCursorPosition().setBlockFormat(nameFormat); +// chatTextTable->cellAt(row,2).firstCursorPosition().setBlockFormat(dateFormat); QTextCursor cur = chatTextTable->cellAt(row,1).firstCursorPosition(); cur.clearSelection(); cur.setKeepPositionOnInsert(true); diff --git a/widget/tool/chataction.cpp b/widget/tool/chataction.cpp index 0847abdda..3587eb600 100644 --- a/widget/tool/chataction.cpp +++ b/widget/tool/chataction.cpp @@ -43,9 +43,9 @@ QString ChatAction::QImage2base64(const QImage &img) QString ChatAction::getName() { if (isMe) - return QString("
" + toHtmlChars(name) + "
"); + return QString("
" + toHtmlChars(name) + "
"); else - return QString("
" + toHtmlChars(name) + "
"); + return QString("
" + toHtmlChars(name) + "
"); } QString ChatAction::getDate() From 77b44fde99f13c5dbc03e1699c06bb8a0132eaac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D1=83=D1=85=D0=B0=D1=80=D0=B8=D0=BA?= Date: Fri, 12 Sep 2014 23:32:31 +0400 Subject: [PATCH 009/205] update russian translation --- translations/ru.qm | Bin 5393 -> 6821 bytes translations/ru.ts | 338 ++++++++++++++++++++++++++++++++------------- 2 files changed, 242 insertions(+), 96 deletions(-) diff --git a/translations/ru.qm b/translations/ru.qm index c772943133073ce31997eb21dd0a3a5bdfb10569..be9acca27be53db64295085b086a990c5702861b 100644 GIT binary patch delta 2933 zcmaJ?Yiv_x7=E{Yy{(sZT?Y$HIGaPnAdGF5ZtT`=uoV~^Fo!6jhxU{m>3T+c##sDO zjgVl_csYthmJFjLB2gd^<2Bw;kf=YrC5E6RMoGM2qQq-ZpYLnet&X{5{m%EE_wu~Y zdpVEXaLAu(cqvkP_NURuKP)eMVQRCm6H$a$QCLk1D+qR!zuyfOrhC-BEUzcvrp_M%F8!> z_UJD}wlOv`szYAE_J>{r&=R(P&tpV|yVIvzxy!tC<vp90C=0M`SUXf=zY|(ZPuG$C~DE1u(K?*Xze%S{LY$JiuZ-zSPSMo zfwRi`@aaDQ{O6SQ?8W(Zyo+maGD039oHkE?^$PZ12VMz==^E^t4L^*D{^cQ zb_ZRj&NRSorRz+^CjdO~F&;oEb-2zRfMJ2^E?ZoI+T7wU+aH0!ukM<$%|zCE_qss? zwVUN$xA!Oll6!p_9N7BZ$D$`ux=`WV9jDPFwJPWen&5E`yM|SyfuAdEBak`HXu^B_}R{`_xLf@UvxXHCxKMNn*8d zv;SPo#Wh_TPN=%PC8qFDz7=Xr=}pM-WK>Cn;z?bOhtqVF zv2xaA`0Ptk)9XCTuH_jcUJz#^7;DAJ(Sj*F7$;r_*!Hpv6{jx5_GMp`6B(?QxT2hf@u-C677D`%z*DULjX*oTy(SFWkZ1-%D934trNyxEm<5jXb0Nn`K)%aayZ1&DA_hgiEx^=RpalzA3 zIawfj_#iJ@Hv4Ygs>YpOUkbEv_IX{FK%pZ;X)Va%eAh#<2~Pn*bT#_g4@8g&I{6q? z0a-16TOj2~>+oi(H7^hE&+*ZNXF+_5w}1P3&QmfoeVlAg-msR~hG_(U2_>v+i4jRf z7bEPXwnG9YJamxbr z_6%)_sbMJ;k0PL$cAnx?mrg?|D$fxcedg=BawH-hA7-+Ob&^EAq|r{CA!^UYb6}7X zQm?jC3bjuOWRw;+ItsdEHNHWON3>yMQ*mF;{pI5MIrodjYjf_+zUxwx>;;}`HWPTN zQJ@yq$<~fDfReXo3f_d>linb_S36iBi}sp6RT)MX4GhKNsZuCWUHc!s-@X)60N!{ zn-B{Q%L312)dJDkjSLHWLa}uyIYrUQykf)gPvk^%Te{;hHI5}!hBcQ#um`YRMR`{i OIR5eFvnvY=ivI;q1%K-R delta 1472 zcmZWoT})eL7=BB?(?8m>779yg#&P`XNQP?%6k4Fj&wz!<3d?4qmiDkVbUozsu+R%_ z7B|C!k!(lY6cYTIUg*V0Se9-6FrpWR>DA_i8a2@iz0!;MyTs{pPNB%iNzeD4_vd+^ z_j%vG<2(Oow(WXs_xi7k^ItsTS$+1+kG>5N>8=w!6(@2o5PLU6WVlaUpO2_0N;PYh zM7t8?eZYuJ&r|1=Lc|Qze{i12@iPtizk>fZE&OvA`K7e<42QfT{h{*vi2p^ue(@|3 zeW3sH!aXA6D$8USWjI3Y(#$JFg-_>B>uvUW3%+gj?EN_%fKu#A`7t8<0{gJ)H==?! z*q;kO0%(Yf@UF-$r2z*B-Be{SWS?!plVFL)_flIpkGw@6CP!A}@2-F5e~6 zpEXRlZvp>;AuC$D(cv|N_{0bpwHPv^6$o52>UOJyJ~mpaFTx+soz`jN`cE%_&^?px z^cfH-Fl7hdBH~8OGmBv;mo}pGFHT4Vj_V6ZFrTw~F2z8o)IK~3$sM!y;n^zy zykS4$LA-IszC3;v(O)NsiW^p5D>%kw-E0r*W6i9Q`PqKr)i-NnKGwkoOe(YizrwD_ zNkNM6f+R{t)t39#>2W{9s#p-wZO994&nKR$sS&mS^Woi&I4>R*`yeVljtpOxg;*yW zqJ6nA7=x?{U_pcgSP<4`_|?=_HV98pOAE0=NOVJVVIj|-A~G!Z)?$SXH2-{_U!orjer zXR*@iys5nC=veu|xmTwwmGx&sREN&@qyIKk4QbLfX|i={UH8Hk#JC2aKqoZV!H(+l z{7UMg$wYL5j|&p|75OMw)~kH2M+8|;q)w!Jpp!O7KXU@Cl_`t%q+4O?U91=PbU;L}z@ zm7tmVl(nJ~WyxjE+D6iX#BXxhfv=(UKw`hTUKng{>mfMg^g{Lko&nZ^FLepke?map zYwR$*el($Ot{T53b9vp^lq`!WK9TZ7qH^LC7Hdk9gp{1j$!*9@Ua52ijGOlf*J%F! xxvMsRf8csDe?MMY^VmkbM%+MQ5@|X=Uwv4dR$JV}{JXRvpW9e=K$&&B{{sPmR$~AF diff --git a/translations/ru.ts b/translations/ru.ts index 1e2118770..6273249e8 100644 --- a/translations/ru.ts +++ b/translations/ru.ts @@ -1,77 +1,91 @@ + + AVPage + + + Video Settings + Настройки видео + + AddFriendForm - + Add Friends Добавление друзей - + Tox ID Tox ID of the person you're sending a friend request to Tox ID - + Message The message you send in friend requests Сообщение - + Send friend request Мне не нравится, но другого не придумал, и фейсбук использует это Отправить запрос на добавление в друзья - + Tox me maybe? Default message in friend requests if the field is left blank. Write something appropriate! Вот таким нехитрым и незамысловатым образом решаются сложные переводчиские проблемы Добавь меня, а? - + Please fill in a valid Tox ID Tox ID of the friend you're sending a friend request to Пожалуйста, введите корректный Tox ID - + + You can't add yourself as a friend ! + When trying to add your own Tox ID as friend + Нельзя добавить самого себя в друзья! + + + This address does not exist The DNS gives the Tox ID associated to toxme.se addresses Нет такого адреса - + Error while looking up DNS The DNS gives the Tox ID associated to toxme.se addresses Ошибка при просмотре DNS - + Unexpected number of text records Error with the DNS Непредвиденное количество текстовых записей - + Unexpected number of values in text record Error with the DNS Непредвиденное количество значений в текстовой записи - + The DNS lookup does not contain any Tox ID Error with the DNS В ответе DNS ни одного Tox ID - + The DNS lookup does not contain a valid Tox ID Error with the DNS Ответ DNS не содержит корректных Tox ID @@ -80,74 +94,87 @@ Camera - Camera eror - Ошибка камеры + Ошибка камеры - Camera format %1 not supported, can't use the camera - Формат камеры %1 не поддерживается, невозможно использовать камеру + Формат камеры %1 не поддерживается, невозможно использовать камеру ChatForm - + Send a file Отправить файл - - Save chat log - Сохранить лог чата + Сохранить лог чата CopyableElideLabel - Copy - Копировать + Копировать - FileTransfertWidget + FileTransferInstance - + Save a file Title of the file saving dialog Сохранить файл - + Location not writable Title of permissions popup - + Непригодная для записи локация - + You do not have permission to write that location. Choose another, or cancel the save dialog. text of permissions popup - + У вас нет прав записи в эту локацию. Выберете другую или закройте диалог сохранения. + + + + FileTransfertWidget + + Save a file + Title of the file saving dialog + Сохранить файл + + + Location not writable + Title of permissions popup + Непригодная для записи локация + + + You do not have permission to write that location. Choose another, or cancel the save dialog. + text of permissions popup + У вас нет прав записи в эту локацию. Выберете другую или закройте диалог сохранения. FilesForm - + Transfered Files "Headline" of the window Переданные файлы - + Downloads Загрузки - + Uploads Выгрузки @@ -193,246 +220,365 @@ FriendWidget - + Copy friend ID Menu to copy the Tox ID of that friend Копировать ID друга - + Invite in group Menu to invite a friend in a groupchat Пригласить в группу - + Remove friend Menu to remove the friend from our friendlist Удалить друга - GroupChatForm + GeneralPage - - %1 users in chat - Number of users in chat - %1 пользователей в чате + + General Settings + Основные настройки - - <Unknown> - <Неизвестно> + + Enable IPv6 (recommended) + Text on a checkbox to enable IPv6 + Включить IPv6 (рекомендуется) - - %1 users in chat - %1 пользователей в чате + + Use translations + Text on a checkbox to enable translations + Русскоязычный интерфейс - + + Make Tox portable + Text on a checkbox to make qTox a portable application + Портативный режим + + + + Save settings to the working directory instead of the usual conf dir + describes makeToxPortable checkbox + Сохранять настройки в рабочую директорию вместо страндартной директории настроек + + + + Theme + Тема + + + + Smiley Pack + Набор смайликов + + + + GenericChatForm + + + Save chat log Сохранить лог чата + + GroupChatForm + + + %1 users in chat + Number of users in chat + %1 пользователей в чате + + + + <Unknown> + <Неизвестно> + + + + %1 users in chat + %1 пользователей в чате + + + Save chat log + Сохранить лог чата + + GroupWidget - + Quit group Menu to quit a groupchat Покинуть группу - - + + %1 users in chat %1 пользователей в чате - - + + 0 users in chat Ни одного пользователя в чате + + IdentityPage + + + Public Information + Публичные данные + + + + Name + Username/nick + Имя + + + + Status + Status message + Статус + + + + Tox ID + Tox ID + + + + Your Tox ID + Ваш Tox ID + + MainWindow qTox - + qTox Your name - Ваше имя + Ваше имя Your status - Ваш статус + Ваш статус Add friends - Добавить друзей + Добавить друзей Create a group chat - Создать групповой чат + Создать групповой чат View completed file transfers - + Завершённые файлопередачи Change your settings - Изменить ваши настройки + Изменить ваши настройки Close - Закрыть + Закрыть Ctrl+Q - Ctrl+Q + Ctrl+Q SelfCamView - + Tox video test Title of the window to test the video/webcam Проверка видео + + SettingsDialog + + + Settings Dialog + Диалог настроек + + + + General + Основное + + + + Identity + Личные данные + + + + Privacy + Безопасность + + + + Audio/Video + Аудио и видео + + + + Ok + ОК + + + + Cancel + Отмена + + + + Apply + Применить + + SettingsForm - User Settings "Headline" of the window - Пользовательские настройки + Пользовательские настройки - Name Username/nick - Имя + Имя - Status Status message - Статус + Статус - (click here to copy) Click on this text to copy TID to clipboard - (нажмите здесь чтобы скопировать) + (нажмите здесь чтобы скопировать) - Test video Text on a button to test the video/webcam - Проверить видео + Проверить видео - Enable IPv6 (recommended) Text on a checkbox to enable IPv6 - Включить IPv6 (рекомендуется) + Включить IPv6 (рекомендуется) - Use translations Text on a checkbox to enable translations Так гораздо понятнее, чем «использовать переводы» - Русскоязычный интерфейс + Русскоязычный интерфейс - Make Tox portable Text on a checkbox to make qTox a portable application - Портативный режим + Портативный режим - Save settings to the working directory instead of the usual conf dir describes makeToxPortable checkbox - + Сохранять настройки в рабочую директорию вместо страндартной директории настроек - Smiley Pack Text on smiley pack label - + Набор смайликов Widget Tox - Tox + Tox Your name - Ваше имя + Ваше имя Your status - Ваш статус + Ваш статус Add friends - Добавить друзей + Добавить друзей Create a group chat - Создать групповой чат + Создать групповой чат (button inactive currently) - (кнопка на данный момент неактивна) + (кнопка на данный момент неактивна) Change your settings - Изменить ваши настройки + Изменить ваши настройки Close - Закрыть + Закрыть Ctrl+Q - Ctrl+Q + Ctrl+Q - + Online Button to set your status to 'Online' - В сети + В сети - + Away Button to set your status to 'Away' Вероятно, это не столь долгое путешествие - Отошёл + Отошёл - + Busy Button to set your status to 'Busy' - Занят + Занят + + + + <Unknown> + Placeholder when we don't know someone's name in a group chat + <Неизвестно> From 7e577359fd64d51983a22f36bf8ec91743875589 Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Fri, 12 Sep 2014 21:38:38 +0200 Subject: [PATCH 010/205] Improve chat form performance Should help with #266 --- widget/chatareawidget.cpp | 7 +++---- widget/tool/chataction.cpp | 6 +++--- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/widget/chatareawidget.cpp b/widget/chatareawidget.cpp index 199420e9f..f06ec9534 100644 --- a/widget/chatareawidget.cpp +++ b/widget/chatareawidget.cpp @@ -20,6 +20,7 @@ #include #include #include +#include ChatAreaWidget::ChatAreaWidget(QWidget *parent) : QTextBrowser(parent) @@ -104,15 +105,13 @@ void ChatAreaWidget::insertMessage(ChatAction *msgAction) checkSlider(); int row = chatTextTable->rows() - 1; -// chatTextTable->cellAt(row,0).firstCursorPosition().setBlockFormat(nameFormat); -// chatTextTable->cellAt(row,2).firstCursorPosition().setBlockFormat(dateFormat); QTextCursor cur = chatTextTable->cellAt(row,1).firstCursorPosition(); cur.clearSelection(); cur.setKeepPositionOnInsert(true); + chatTextTable->appendRows(1); chatTextTable->cellAt(row,0).firstCursorPosition().insertHtml(msgAction->getName()); chatTextTable->cellAt(row,1).firstCursorPosition().insertHtml(msgAction->getMessage()); - chatTextTable->cellAt(row,2).firstCursorPosition().insertHtml(msgAction->getDate()); - chatTextTable->appendRows(1); + chatTextTable->cellAt(row,2).firstCursorPosition().insertText(msgAction->getDate()); msgAction->setTextCursor(cur); diff --git a/widget/tool/chataction.cpp b/widget/tool/chataction.cpp index 3587eb600..6625b061f 100644 --- a/widget/tool/chataction.cpp +++ b/widget/tool/chataction.cpp @@ -43,14 +43,14 @@ QString ChatAction::QImage2base64(const QImage &img) QString ChatAction::getName() { if (isMe) - return QString("
" + toHtmlChars(name) + "
"); + return QString("
" + toHtmlChars(name) + "
"); else - return QString("
" + toHtmlChars(name) + "
"); + return QString("
" + toHtmlChars(name) + "
"); } QString ChatAction::getDate() { - QString res = "
" + date + "
"; + QString res = date; return res; } From 70079015c73e1271eda3d14a78d18ddbdce2d1f4 Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Fri, 12 Sep 2014 21:57:33 +0200 Subject: [PATCH 011/205] Update translations, add Polish --- translations/de.ts | 285 ++++++++++++++++++++--------- translations/fr.ts | 285 ++++++++++++++++++++--------- translations/it.ts | 227 +++++++++++++++++------ translations/po.ts | 445 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 1017 insertions(+), 225 deletions(-) create mode 100644 translations/po.ts diff --git a/translations/de.ts b/translations/de.ts index ab61ba9ad..3c2a7284c 100644 --- a/translations/de.ts +++ b/translations/de.ts @@ -1,75 +1,89 @@ + + AVPage + + + Video Settings + + + AddFriendForm - + Add Friends Freunde hinzufügen - + Tox ID Tox ID of the person you're sending a friend request to Tox ID - + Message The message you send in friend requests Nachricht - + Send friend request Freundschaftseinladung versenden - + Tox me maybe? Default message in friend requests if the field is left blank. Write something appropriate! Lass uns Toxen! - + Please fill in a valid Tox ID Tox ID of the friend you're sending a friend request to Bitte gib eine gültige Tox ID ein - + + You can't add yourself as a friend ! + When trying to add your own Tox ID as friend + + + + This address does not exist The DNS gives the Tox ID associated to toxme.se addresses - + Error while looking up DNS The DNS gives the Tox ID associated to toxme.se addresses Fehler beim Auflösen des DNS - + Unexpected number of text records Error with the DNS Unererwartete Anzahl von Texteinträgen - + Unexpected number of values in text record Error with the DNS Unerwartete Anzahl von Werten innerhalb des Texteintrages - + The DNS lookup does not contain any Tox ID Error with the DNS Der DNS Eintrag enthält keine gültige TOX ID - + The DNS lookup does not contain a valid Tox ID Error with the DNS Der DNS Eintrag enthält keine gültige TOX ID @@ -78,74 +92,77 @@ Camera - Camera eror - Kamerafehler + Kamerafehler - Camera format %1 not supported, can't use the camera - Kameraformat %1 wird nicht unterstützt. Die Kamera kann nicht verwendet werden + Kameraformat %1 wird nicht unterstützt. Die Kamera kann nicht verwendet werden ChatForm - + Send a file Datei versenden - - Save chat log - Chatverlauf speichern + Chatverlauf speichern CopyableElideLabel - Copy - Kopieren + Kopieren - FileTransfertWidget + FileTransferInstance - + Save a file Title of the file saving dialog - Datei speichern + Datei speichern - + Location not writable Title of permissions popup - + You do not have permission to write that location. Choose another, or cancel the save dialog. text of permissions popup + + FileTransfertWidget + + Save a file + Title of the file saving dialog + Datei speichern + + FilesForm - + Transfered Files "Headline" of the window - + Downloads - + Uploads @@ -189,69 +206,149 @@ FriendWidget - + Copy friend ID Menu to copy the Tox ID of that friend Tox ID kopieren - + Invite in group Menu to invite a friend in a groupchat In Gruppe einladen - + Remove friend Menu to remove the friend from our friendlist Freund entfernen + + GeneralPage + + + General Settings + + + + + Enable IPv6 (recommended) + Text on a checkbox to enable IPv6 + IPv6 aktivieren (empfohlen) + + + + Use translations + Text on a checkbox to enable translations + + + + + Make Tox portable + Text on a checkbox to make qTox a portable application + + + + + Save settings to the working directory instead of the usual conf dir + describes makeToxPortable checkbox + + + + + Theme + + + + + Smiley Pack + + + + + GenericChatForm + + + + Save chat log + Chatverlauf speichern + + GroupChatForm - + %1 users in chat Number of users in chat %1 Personen im Chat - + <Unknown> <Unbekannt> - + %1 users in chat %1 Personen im Chat - Save chat log - Chatverlauf speichern + Chatverlauf speichern GroupWidget - - + + %1 users in chat %1 Personen im Chat - - + + 0 users in chat 0 Personen im Chat - + Quit group Menu to quit a groupchat Gruppe verlassen + + IdentityPage + + + Public Information + + + + + Name + Username/nick + Benutzername + + + + Status + Status message + Status + + + + Tox ID + Tox ID + + + + Your Tox ID + + + MainWindow @@ -303,73 +400,81 @@ SelfCamView - + Tox video test Title of the window to test the video/webcam Tox Video testen + + SettingsDialog + + + Settings Dialog + + + + + General + + + + + Identity + + + + + Privacy + + + + + Audio/Video + + + + + Ok + + + + + Cancel + + + + + Apply + + + SettingsForm - User Settings "Headline" of the window - Einstellungen + Einstellungen - Name Username/nick - Benutzername + Benutzername - Status Status message - Status + Status - - (click here to copy) - Click on this text to copy TID to clipboard - - - - Test video Text on a button to test the video/webcam - Video testen + Video testen - Enable IPv6 (recommended) Text on a checkbox to enable IPv6 - IPv6 aktivieren (empfohlen) - - - - Use translations - Text on a checkbox to enable translations - - - - - Make Tox portable - Text on a checkbox to make qTox a portable application - - - - - Save settings to the working directory instead of the usual conf dir - describes makeToxPortable checkbox - - - - - Smiley Pack - Text on smiley pack label - + IPv6 aktivieren (empfohlen) @@ -395,22 +500,28 @@ Strg+Q - + Online Button to set your status to 'Online' Online - + Away Button to set your status to 'Away' Abwesend - + Busy Button to set your status to 'Busy' Beschäftigt + + + <Unknown> + Placeholder when we don't know someone's name in a group chat + <Unbekannt> + diff --git a/translations/fr.ts b/translations/fr.ts index 435d022c7..50d9b31e1 100644 --- a/translations/fr.ts +++ b/translations/fr.ts @@ -1,75 +1,89 @@ + + AVPage + + + Video Settings + + + AddFriendForm - + Add Friends Ajouter des amis - + Tox ID Tox ID of the person you're sending a friend request to ID Tox - + Message The message you send in friend requests Message - + Send friend request Envoyer la demande d'ami - + Tox me maybe? Default message in friend requests if the field is left blank. Write something appropriate! Je souhaiterais vous ajouter à mes contacts - + Please fill in a valid Tox ID Tox ID of the friend you're sending a friend request to Merci de remplir un ID Tox valide - + + You can't add yourself as a friend ! + When trying to add your own Tox ID as friend + + + + This address does not exist The DNS gives the Tox ID associated to toxme.se addresses - + Error while looking up DNS The DNS gives the Tox ID associated to toxme.se addresses Erreur en consultant le serveur DNS - + Unexpected number of text records Error with the DNS Nombre d'entrées texte innatendu - + Unexpected number of values in text record Error with the DNS Nombre d'entrées numériques dans l'entrée texte innatendu - + The DNS lookup does not contain any Tox ID Error with the DNS La réponse DNS ne contient aucun ID Tox - + The DNS lookup does not contain a valid Tox ID Error with the DNS La réponse DNS ne contient pas d'ID Tox valide @@ -78,74 +92,77 @@ Camera - Camera eror - Erreur de caméra + Erreur de caméra - Camera format %1 not supported, can't use the camera - Format %1 de la caméra non supporté, impossible de l'utiliser + Format %1 de la caméra non supporté, impossible de l'utiliser ChatForm - + Send a file Envoyer un fichier - - Save chat log - Sauvegarder l'historique de conversation + Sauvegarder l'historique de conversation CopyableElideLabel - Copy - Copier + Copier - FileTransfertWidget + FileTransferInstance - + Save a file Title of the file saving dialog - Sauvegarder un fichier + Sauvegarder un fichier - + Location not writable Title of permissions popup - + You do not have permission to write that location. Choose another, or cancel the save dialog. text of permissions popup + + FileTransfertWidget + + Save a file + Title of the file saving dialog + Sauvegarder un fichier + + FilesForm - + Transfered Files "Headline" of the window - + Downloads - + Uploads @@ -189,69 +206,149 @@ FriendWidget - + Copy friend ID Menu to copy the Tox ID of that friend Copier l'ID ami - + Invite in group Menu to invite a friend in a groupchat Inviter dans un groupe - + Remove friend Menu to remove the friend from our friendlist Supprimer ami + + GeneralPage + + + General Settings + + + + + Enable IPv6 (recommended) + Text on a checkbox to enable IPv6 + Activer IPv6 (recommandé) + + + + Use translations + Text on a checkbox to enable translations + + + + + Make Tox portable + Text on a checkbox to make qTox a portable application + + + + + Save settings to the working directory instead of the usual conf dir + describes makeToxPortable checkbox + + + + + Theme + + + + + Smiley Pack + + + + + GenericChatForm + + + + Save chat log + Sauvegarder l'historique de conversation + + GroupChatForm - + %1 users in chat Number of users in chat %1 personnes - + <Unknown> <Inconnu> - + %1 users in chat %1 personnes - Save chat log - Sauvegarder l'historique de conversation + Sauvegarder l'historique de conversation GroupWidget - - + + %1 users in chat %1 personnes - - + + 0 users in chat 0 personnes - + Quit group Menu to quit a groupchat Quitter le groupe + + IdentityPage + + + Public Information + + + + + Name + Username/nick + Nom + + + + Status + Status message + Status + + + + Tox ID + ID Tox + + + + Your Tox ID + + + MainWindow @@ -303,73 +400,81 @@ SelfCamView - + Tox video test Title of the window to test the video/webcam Test vidéo Tox + + SettingsDialog + + + Settings Dialog + + + + + General + + + + + Identity + + + + + Privacy + + + + + Audio/Video + + + + + Ok + + + + + Cancel + + + + + Apply + + + SettingsForm - User Settings "Headline" of the window - Configuration + Configuration - Name Username/nick - Nom + Nom - Status Status message - Status + Status - - (click here to copy) - Click on this text to copy TID to clipboard - - - - Test video Text on a button to test the video/webcam - Tester la vidéo + Tester la vidéo - Enable IPv6 (recommended) Text on a checkbox to enable IPv6 - Activer IPv6 (recommandé) - - - - Use translations - Text on a checkbox to enable translations - - - - - Make Tox portable - Text on a checkbox to make qTox a portable application - - - - - Save settings to the working directory instead of the usual conf dir - describes makeToxPortable checkbox - - - - - Smiley Pack - Text on smiley pack label - + Activer IPv6 (recommandé) @@ -395,22 +500,28 @@ Ctrl+Q - + Online Button to set your status to 'Online' Connecté - + Away Button to set your status to 'Away' Indisponnible - + Busy Button to set your status to 'Busy' Occupé + + + <Unknown> + Placeholder when we don't know someone's name in a group chat + <Inconnu> + diff --git a/translations/it.ts b/translations/it.ts index 65a34eb9f..dad9d73ca 100644 --- a/translations/it.ts +++ b/translations/it.ts @@ -1,75 +1,89 @@ + + AVPage + + + Video Settings + + + AddFriendForm - + Add Friends Aggiungi Contatto - + Tox ID Tox ID of the person you're sending a friend request to Tox ID - + Message The message you send in friend requests Messaggio - + Send friend request Invia richiesta d'amicizia - + Tox me maybe? Default message in friend requests if the field is left blank. Write something appropriate! Permettimi di aggiungerti alla mia lista contatti - + Please fill in a valid Tox ID Tox ID of the friend you're sending a friend request to Inserisci un Tox ID valido - + + You can't add yourself as a friend ! + When trying to add your own Tox ID as friend + + + + This address does not exist The DNS gives the Tox ID associated to toxme.se addresses Questo indirizzo non esiste - + Error while looking up DNS The DNS gives the Tox ID associated to toxme.se addresses Errore nel consultare il server DNS - + Unexpected number of text records Error with the DNS Numero inaspettato di text-records - + Unexpected number of values in text record Error with the DNS Numero inaspettato di valori nel text-record - + The DNS lookup does not contain any Tox ID Error with the DNS La risposta del server DNS non contiene nessun Tox ID - + The DNS lookup does not contain a valid Tox ID Error with the DNS La risposta del server DNS non contiene un Tox ID valido @@ -78,7 +92,7 @@ ChatForm - + Send a file Invia un file @@ -86,19 +100,19 @@ FileTransferInstance - + Save a file Title of the file saving dialog Salva file - + Location not writable Title of permissions popup Errore - + You do not have permission to write that location. Choose another, or cancel the save dialog. text of permissions popup Non hai sufficienti permessi per scrivere in questa locazione. Scegli un'altra posizione, o annulla il salvataggio. @@ -107,18 +121,18 @@ FilesForm - + Transfered Files "Headline" of the window Files Trasferiti - + Downloads Ricevuti - + Uploads Inviati @@ -162,29 +176,71 @@ FriendWidget - + Copy friend ID Menu to copy the Tox ID of that friend Copia Tox ID del contatto - + Invite in group Menu to invite a friend in a groupchat Invita nel gruppo - + Remove friend Menu to remove the friend from our friendlist Rimuovi contatto + + GeneralPage + + + General Settings + + + + + Enable IPv6 (recommended) + Text on a checkbox to enable IPv6 + Abilita IPv6 (consigliato) + + + + Use translations + Text on a checkbox to enable translations + Abilita traduzioni + + + + Make Tox portable + Text on a checkbox to make qTox a portable application + Rendi qTox portabile + + + + Save settings to the working directory instead of the usual conf dir + describes makeToxPortable checkbox + Slava le impostazioni nella directory di lavoro corrente, invece della directory di default + + + + Theme + + + + + Smiley Pack + Emoticons + + GenericChatForm - - + + Save chat log Salva il log della chat @@ -192,18 +248,18 @@ GroupChatForm - + %1 users in chat Number of users in chat %1 utenti in chat - + <Unknown> <Sconosciuto> - + %1 users in chat %1 utenti in chat @@ -229,6 +285,36 @@ Esci dal gruppo + + IdentityPage + + + Public Information + + + + + Name + Username/nick + Nome + + + + Status + Status message + Stato + + + + Tox ID + Tox ID + + + + Your Tox ID + + + MainWindow @@ -280,94 +366,133 @@ SelfCamView - + Tox video test Title of the window to test the video/webcam qTox video test + + SettingsDialog + + + Settings Dialog + + + + + General + + + + + Identity + + + + + Privacy + + + + + Audio/Video + + + + + Ok + + + + + Cancel + + + + + Apply + + + SettingsForm - User Settings "Headline" of the window - Impostazioni + Impostazioni - Name Username/nick - Nome + Nome - Status Status message - Stato + Stato - (click here to copy) Click on this text to copy TID to clipboard - (clicca qui per copiare) + (clicca qui per copiare) - Test video Text on a button to test the video/webcam - Prova la webcam + Prova la webcam - Enable IPv6 (recommended) Text on a checkbox to enable IPv6 - Abilita IPv6 (consigliato) + Abilita IPv6 (consigliato) - Use translations Text on a checkbox to enable translations - Abilita traduzioni + Abilita traduzioni - Make Tox portable Text on a checkbox to make qTox a portable application - Rendi qTox portabile + Rendi qTox portabile - Save settings to the working directory instead of the usual conf dir describes makeToxPortable checkbox - Slava le impostazioni nella directory di lavoro corrente, invece della directory di default + Slava le impostazioni nella directory di lavoro corrente, invece della directory di default - Smiley Pack Text on smiley pack label - Emoticons + Emoticons Widget - + Online Button to set your status to 'Online' Online - + Away Button to set your status to 'Away' Assente - + Busy Button to set your status to 'Busy' Occupato + + + <Unknown> + Placeholder when we don't know someone's name in a group chat + <Sconosciuto> + diff --git a/translations/po.ts b/translations/po.ts new file mode 100644 index 000000000..f3a5a3144 --- /dev/null +++ b/translations/po.ts @@ -0,0 +1,445 @@ + + + + + AVPage + + + Video Settings + + + + + AddFriendForm + + + Add Friends + + + + + Tox ID + Tox ID of the person you're sending a friend request to + + + + + Message + The message you send in friend requests + + + + + Send friend request + + + + + Tox me maybe? + Default message in friend requests if the field is left blank. Write something appropriate! + + + + + Please fill in a valid Tox ID + Tox ID of the friend you're sending a friend request to + + + + + You can't add yourself as a friend ! + When trying to add your own Tox ID as friend + + + + + This address does not exist + The DNS gives the Tox ID associated to toxme.se addresses + + + + + Error while looking up DNS + The DNS gives the Tox ID associated to toxme.se addresses + + + + + Unexpected number of text records + Error with the DNS + + + + + Unexpected number of values in text record + Error with the DNS + + + + + The DNS lookup does not contain any Tox ID + Error with the DNS + + + + + + The DNS lookup does not contain a valid Tox ID + Error with the DNS + + + + + ChatForm + + + Send a file + + + + + FileTransferInstance + + + Save a file + Title of the file saving dialog + + + + + Location not writable + Title of permissions popup + + + + + You do not have permission to write that location. Choose another, or cancel the save dialog. + text of permissions popup + + + + + FilesForm + + + Transfered Files + "Headline" of the window + + + + + Downloads + + + + + Uploads + + + + + FriendRequestDialog + + + Friend request + Title of the window to aceept/deny a friend request + + + + + Someone wants to make friends with you + + + + + User ID: + + + + + Friend request message: + + + + + Accept + Accept a friend request + + + + + Reject + Reject a friend request + + + + + FriendWidget + + + Copy friend ID + Menu to copy the Tox ID of that friend + + + + + Invite in group + Menu to invite a friend in a groupchat + + + + + Remove friend + Menu to remove the friend from our friendlist + + + + + GeneralPage + + + General Settings + + + + + Enable IPv6 (recommended) + Text on a checkbox to enable IPv6 + + + + + Use translations + Text on a checkbox to enable translations + + + + + Make Tox portable + Text on a checkbox to make qTox a portable application + + + + + Save settings to the working directory instead of the usual conf dir + describes makeToxPortable checkbox + + + + + Theme + + + + + Smiley Pack + + + + + GenericChatForm + + + + Save chat log + + + + + GroupChatForm + + + %1 users in chat + Number of users in chat + + + + + <Unknown> + + + + + %1 users in chat + + + + + GroupWidget + + + + %1 users in chat + + + + + + 0 users in chat + + + + + Quit group + Menu to quit a groupchat + + + + + IdentityPage + + + Public Information + + + + + Name + Username/nick + + + + + Status + Status message + + + + + Tox ID + + + + + Your Tox ID + + + + + MainWindow + + + qTox + + + + + Your name + + + + + Your status + + + + + Add friends + + + + + Create a group chat + + + + + View completed file transfers + + + + + Change your settings + + + + + Close + + + + + Ctrl+Q + + + + + SelfCamView + + + Tox video test + Title of the window to test the video/webcam + + + + + SettingsDialog + + + Settings Dialog + + + + + General + + + + + Identity + + + + + Privacy + + + + + Audio/Video + + + + + Ok + + + + + Cancel + + + + + Apply + + + + + Widget + + + Online + Button to set your status to 'Online' + + + + + Away + Button to set your status to 'Away' + + + + + Busy + Button to set your status to 'Busy' + + + + + <Unknown> + Placeholder when we don't know someone's name in a group chat + + + + From e9fa8de43d13555ea36531e362c5786ab4c48ece Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Fri, 12 Sep 2014 21:59:49 +0200 Subject: [PATCH 012/205] Enable Polish translation --- qtox.pro | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/qtox.pro b/qtox.pro index 96e609c33..19413ea0d 100644 --- a/qtox.pro +++ b/qtox.pro @@ -32,7 +32,8 @@ CONFIG += c++11 TRANSLATIONS = translations/de.ts \ translations/fr.ts \ translations/it.ts \ - translations/ru.ts + translations/ru.ts \ + translations/po.ts RESOURCES += res.qrc From b6ccbfc62fffd19449114ab0e0f112d9bf6a8b60 Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Fri, 12 Sep 2014 22:24:29 +0200 Subject: [PATCH 013/205] Fix greentext Thanks to dewbasaur for reporting the bug --- ui/chatArea/innerStyle.css | 4 ++-- widget/tool/chataction.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ui/chatArea/innerStyle.css b/ui/chatArea/innerStyle.css index 61380b073..28bcb32c8 100644 --- a/ui/chatArea/innerStyle.css +++ b/ui/chatArea/innerStyle.css @@ -22,8 +22,8 @@ div.date { white-space: nowrap; } -div.quote { - background-color: #6bc260; +span.quote { + color: #6bc260; } div.green { diff --git a/widget/tool/chataction.cpp b/widget/tool/chataction.cpp index 6625b061f..bcd1f1080 100644 --- a/widget/tool/chataction.cpp +++ b/widget/tool/chataction.cpp @@ -102,9 +102,9 @@ QString MessageAction::getMessage() for (QString& s : messageLines) { if (QRegExp("^[ ]*>.*").exactMatch(s)) - message_ += "
" + s.right(s.length()-4) + "

"; + message_ += ">" + s.right(s.length()-4) + "
"; else - message_ += s + "
"; + message_ += s + "
"; } message_ = message_.left(message_.length()-4); From 904a584d75ec8d2abed1d3c10f2cf306ff881f1a Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Fri, 12 Sep 2014 23:35:44 +0200 Subject: [PATCH 014/205] Change video preview button text --- widget/settingsdialog.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/widget/settingsdialog.cpp b/widget/settingsdialog.cpp index 4f9c26a9b..c4b764043 100644 --- a/widget/settingsdialog.cpp +++ b/widget/settingsdialog.cpp @@ -131,7 +131,7 @@ public: camView = new SelfCamView(parent->getWidget()->getCamera()); camView->hide(); // hide by default - testVideo = new QPushButton("enable video"); + testVideo = new QPushButton("Show video preview"); connect(testVideo, SIGNAL(clicked()), this, SLOT(onTestVideoPressed())); QVBoxLayout *vLayout = new QVBoxLayout(); @@ -152,13 +152,13 @@ public: void showTestVideo() { - testVideo->setText("disable video"); + testVideo->setText("Hide video preview"); camView->show(); } void closeTestVideo() { - testVideo->setText("enable video"); + testVideo->setText("Show video preview"); camView->close(); } From 627e5b178b1fe9bac3469b03f5f3136f2b36c3fc Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Fri, 12 Sep 2014 23:41:13 +0200 Subject: [PATCH 015/205] Change settings dialog title --- widget/settingsdialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/widget/settingsdialog.cpp b/widget/settingsdialog.cpp index c4b764043..05ce3c165 100644 --- a/widget/settingsdialog.cpp +++ b/widget/settingsdialog.cpp @@ -192,7 +192,7 @@ SettingsDialog::SettingsDialog(Widget *parent) : createButtons(); createConnections(); createLayout(); - setWindowTitle(tr("Settings Dialog")); + setWindowTitle(tr("qTox – Settings")); } void SettingsDialog::createPages() From 5c1ae49f81508dc5ed4daf7c47f63747239f77e8 Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Fri, 12 Sep 2014 23:55:37 +0200 Subject: [PATCH 016/205] Typo --- widget/form/addfriendform.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/widget/form/addfriendform.cpp b/widget/form/addfriendform.cpp index 2c9b197b2..55f5e80dd 100644 --- a/widget/form/addfriendform.cpp +++ b/widget/form/addfriendform.cpp @@ -96,7 +96,7 @@ void AddFriendForm::onSendTriggered() showWarning(tr("Please fill in a valid Tox ID","Tox ID of the friend you're sending a friend request to")); } else if (isToxId(id)) { if (id.toUpper() == Core::getInstance()->getSelfId().toString().toUpper()) - showWarning(tr("You can't add yourself as a friend !","When trying to add your own Tox ID as friend")); + showWarning(tr("You can't add yourself as a friend!","When trying to add your own Tox ID as friend")); else emit friendRequested(id, getMessage()); this->toxId.setText(""); From 965c76a31545c61303d4485c4326887cc6ba4ba3 Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Sat, 13 Sep 2014 00:07:25 +0200 Subject: [PATCH 017/205] Add Manol translation Ayy ! You have mothafucking friend request you little bitch ! --- qtox.pro | 3 +- translations/de.ts | 4 +- translations/fr.ts | 4 +- translations/it.ts | 4 +- translations/mannol.ts | 445 +++++++++++++++++++++++++++++++++++++++++ translations/po.ts | 4 +- translations/ru.ts | 15 +- 7 files changed, 467 insertions(+), 12 deletions(-) create mode 100644 translations/mannol.ts diff --git a/qtox.pro b/qtox.pro index 19413ea0d..b733387b8 100644 --- a/qtox.pro +++ b/qtox.pro @@ -33,7 +33,8 @@ TRANSLATIONS = translations/de.ts \ translations/fr.ts \ translations/it.ts \ translations/ru.ts \ - translations/po.ts + translations/po.ts \ + translations/mannol.ts RESOURCES += res.qrc diff --git a/translations/de.ts b/translations/de.ts index 3c2a7284c..42adc68f9 100644 --- a/translations/de.ts +++ b/translations/de.ts @@ -47,7 +47,7 @@ - You can't add yourself as a friend ! + You can't add yourself as a friend! When trying to add your own Tox ID as friend @@ -410,7 +410,7 @@ SettingsDialog - Settings Dialog + qTox – Settings diff --git a/translations/fr.ts b/translations/fr.ts index 50d9b31e1..2f61287cb 100644 --- a/translations/fr.ts +++ b/translations/fr.ts @@ -47,7 +47,7 @@ - You can't add yourself as a friend ! + You can't add yourself as a friend! When trying to add your own Tox ID as friend @@ -410,7 +410,7 @@ SettingsDialog - Settings Dialog + qTox – Settings diff --git a/translations/it.ts b/translations/it.ts index dad9d73ca..a7c3f39c0 100644 --- a/translations/it.ts +++ b/translations/it.ts @@ -47,7 +47,7 @@ - You can't add yourself as a friend ! + You can't add yourself as a friend! When trying to add your own Tox ID as friend @@ -376,7 +376,7 @@ SettingsDialog - Settings Dialog + qTox – Settings diff --git a/translations/mannol.ts b/translations/mannol.ts new file mode 100644 index 000000000..93b9d0c3c --- /dev/null +++ b/translations/mannol.ts @@ -0,0 +1,445 @@ + + + + + AVPage + + + Video Settings + + + + + AddFriendForm + + + Add Friends + + + + + Tox ID + Tox ID of the person you're sending a friend request to + + + + + Message + The message you send in friend requests + + + + + Send friend request + + + + + Tox me maybe? + Default message in friend requests if the field is left blank. Write something appropriate! + + + + + Please fill in a valid Tox ID + Tox ID of the friend you're sending a friend request to + + + + + You can't add yourself as a friend! + When trying to add your own Tox ID as friend + + + + + This address does not exist + The DNS gives the Tox ID associated to toxme.se addresses + + + + + Error while looking up DNS + The DNS gives the Tox ID associated to toxme.se addresses + + + + + Unexpected number of text records + Error with the DNS + + + + + Unexpected number of values in text record + Error with the DNS + + + + + The DNS lookup does not contain any Tox ID + Error with the DNS + + + + + + The DNS lookup does not contain a valid Tox ID + Error with the DNS + + + + + ChatForm + + + Send a file + + + + + FileTransferInstance + + + Save a file + Title of the file saving dialog + + + + + Location not writable + Title of permissions popup + + + + + You do not have permission to write that location. Choose another, or cancel the save dialog. + text of permissions popup + + + + + FilesForm + + + Transfered Files + "Headline" of the window + + + + + Downloads + + + + + Uploads + + + + + FriendRequestDialog + + + Friend request + Title of the window to aceept/deny a friend request + + + + + Someone wants to make friends with you + + + + + User ID: + + + + + Friend request message: + + + + + Accept + Accept a friend request + + + + + Reject + Reject a friend request + + + + + FriendWidget + + + Copy friend ID + Menu to copy the Tox ID of that friend + + + + + Invite in group + Menu to invite a friend in a groupchat + + + + + Remove friend + Menu to remove the friend from our friendlist + + + + + GeneralPage + + + General Settings + + + + + Enable IPv6 (recommended) + Text on a checkbox to enable IPv6 + + + + + Use translations + Text on a checkbox to enable translations + + + + + Make Tox portable + Text on a checkbox to make qTox a portable application + + + + + Save settings to the working directory instead of the usual conf dir + describes makeToxPortable checkbox + + + + + Theme + + + + + Smiley Pack + + + + + GenericChatForm + + + + Save chat log + + + + + GroupChatForm + + + %1 users in chat + Number of users in chat + + + + + <Unknown> + + + + + %1 users in chat + + + + + GroupWidget + + + + %1 users in chat + + + + + + 0 users in chat + + + + + Quit group + Menu to quit a groupchat + + + + + IdentityPage + + + Public Information + + + + + Name + Username/nick + + + + + Status + Status message + + + + + Tox ID + + + + + Your Tox ID + + + + + MainWindow + + + qTox + + + + + Your name + + + + + Your status + + + + + Add friends + + + + + Create a group chat + + + + + View completed file transfers + + + + + Change your settings + + + + + Close + + + + + Ctrl+Q + + + + + SelfCamView + + + Tox video test + Title of the window to test the video/webcam + + + + + SettingsDialog + + + qTox – Settings + + + + + General + + + + + Identity + + + + + Privacy + + + + + Audio/Video + + + + + Ok + + + + + Cancel + + + + + Apply + + + + + Widget + + + Online + Button to set your status to 'Online' + + + + + Away + Button to set your status to 'Away' + + + + + Busy + Button to set your status to 'Busy' + + + + + <Unknown> + Placeholder when we don't know someone's name in a group chat + + + + diff --git a/translations/po.ts b/translations/po.ts index f3a5a3144..93b9d0c3c 100644 --- a/translations/po.ts +++ b/translations/po.ts @@ -47,7 +47,7 @@ - You can't add yourself as a friend ! + You can't add yourself as a friend! When trying to add your own Tox ID as friend @@ -376,7 +376,7 @@ SettingsDialog - Settings Dialog + qTox – Settings diff --git a/translations/ru.ts b/translations/ru.ts index 6273249e8..87c52b238 100644 --- a/translations/ru.ts +++ b/translations/ru.ts @@ -49,9 +49,14 @@ + You can't add yourself as a friend! + When trying to add your own Tox ID as friend + + + You can't add yourself as a friend ! When trying to add your own Tox ID as friend - Нельзя добавить самого себя в друзья! + Нельзя добавить самого себя в друзья! @@ -423,9 +428,13 @@ SettingsDialog - Settings Dialog - Диалог настроек + Диалог настроек + + + + qTox – Settings + From b2c75dbc5116c0299f0e03badd4411671d6831b6 Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Sat, 13 Sep 2014 00:12:00 +0200 Subject: [PATCH 018/205] Update Mannol translation --- translations/mannol.qm | Bin 0 -> 234 bytes translations/mannol.ts | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 translations/mannol.qm diff --git a/translations/mannol.qm b/translations/mannol.qm new file mode 100644 index 0000000000000000000000000000000000000000..1d4f6d7b644a1b48cc36ba7cefb5673c02d7c4a0 GIT binary patch literal 234 zcmX9&F%E)25L{!TG*&hi7DwYNY&6CPXe{hRSl|NO1vn)54=Zi_g^jT_BtF46_yxx^ zo4K9YotwMqEf}?*%jxBgAG_=QJtrb((4IHwB!Ooa$B|~#pai+VmNZr9F?n<#2Foxp zR)^U5l;EnO2%C@!aE1z?3a}gwrV@UE#D7u>k3pq2ZEuy2JiO=pKGFjwYn`!HENV}g lQWz~VFJTcDl2uTOTAEliy6VF^T-xD^^NLHekY1{z&KDe4II;i$ literal 0 HcmV?d00001 diff --git a/translations/mannol.ts b/translations/mannol.ts index 93b9d0c3c..a1856348e 100644 --- a/translations/mannol.ts +++ b/translations/mannol.ts @@ -148,7 +148,7 @@ Someone wants to make friends with you - + Ayy ! You have mothafucking friend request you little bitch ! From 1a6d2d925e804d5c6c718db791369ed989287d7d Mon Sep 17 00:00:00 2001 From: Zetok Zalbavar Date: Fri, 12 Sep 2014 23:21:02 +0100 Subject: [PATCH 019/205] Add Polish translation --- translations/{po.ts => pl.ts} | 148 +++++++++++++++++----------------- 1 file changed, 76 insertions(+), 72 deletions(-) rename translations/{po.ts => pl.ts} (75%) diff --git a/translations/po.ts b/translations/pl.ts similarity index 75% rename from translations/po.ts rename to translations/pl.ts index 93b9d0c3c..6aaa4e6d6 100644 --- a/translations/po.ts +++ b/translations/pl.ts @@ -1,12 +1,12 @@ - + AVPage Video Settings - + Ustawienia wideo @@ -14,79 +14,79 @@ Add Friends - + Dodaj znajomych Tox ID Tox ID of the person you're sending a friend request to - + Tox ID Message The message you send in friend requests - + Wiadomość Send friend request - + Wyślij zapytanie do znajomego Tox me maybe? Default message in friend requests if the field is left blank. Write something appropriate! - + Może Tox ze mną? Please fill in a valid Tox ID Tox ID of the friend you're sending a friend request to - + Proszę wpisać poprawny Tox ID You can't add yourself as a friend! When trying to add your own Tox ID as friend - + Nie możesz dodać siebie jako znajomego! This address does not exist The DNS gives the Tox ID associated to toxme.se addresses - + Ten adres nie istnieje Error while looking up DNS The DNS gives the Tox ID associated to toxme.se addresses - + Błąd podczas sprawdzania DNS Unexpected number of text records Error with the DNS - + Nieoczekiwana liczba wpisów tekstowych Unexpected number of values in text record Error with the DNS - + Nieoczekiwana liczba wartości we wpisie tekstowym The DNS lookup does not contain any Tox ID Error with the DNS - + DNS nie zawiera żadnego Tox ID The DNS lookup does not contain a valid Tox ID Error with the DNS - + DNS nie zawiera poprawnego Tox ID @@ -94,7 +94,7 @@ Send a file - + Wyślij plik @@ -103,19 +103,19 @@ Save a file Title of the file saving dialog - + Zapisz plik Location not writable Title of permissions popup - + Nie można zapisać w lokacji You do not have permission to write that location. Choose another, or cancel the save dialog. text of permissions popup - + Nie masz uprawnienia by zapisać w tej lokacji. Wybierz inną lub anuluj zapis. @@ -124,17 +124,17 @@ Transfered Files "Headline" of the window - + Przesłane pliki Downloads - + Pobrane Uploads - + Wysłane @@ -143,34 +143,36 @@ Friend request Title of the window to aceept/deny a friend request - + no idea how it shoule be translated + Zapytanie znajomego Someone wants to make friends with you - + Ktoś chce być twoim znajomym User ID: - + ID użytkownika: Friend request message: - + better wording needed? + Wiadomość w zapytaniu do znajomej/go: Accept Accept a friend request - + Zaakceptuj Reject Reject a friend request - + Odrzuć @@ -179,19 +181,19 @@ Copy friend ID Menu to copy the Tox ID of that friend - + Kopiuj ID znajomej/go Invite in group Menu to invite a friend in a groupchat - + Zaproś do grupy Remove friend Menu to remove the friend from our friendlist - + Usuń znajomego @@ -199,41 +201,42 @@ General Settings - + Główne ustawienia Enable IPv6 (recommended) Text on a checkbox to enable IPv6 - + Użyj IPv6 (rekomendowane) Use translations Text on a checkbox to enable translations - + Użyj tłumaczenia Make Tox portable Text on a checkbox to make qTox a portable application - + Zrób Tox przenośnym Save settings to the working directory instead of the usual conf dir describes makeToxPortable checkbox - + Zamiast domyślnego katalogu użyj obecnego do zapisania ustawień Theme - + Motyw Smiley Pack - + needs better translation + Paczka uśmiechów @@ -242,7 +245,7 @@ Save chat log - + Zapisz historię rozmowy @@ -251,17 +254,17 @@ %1 users in chat Number of users in chat - + %1 użytkowników w czacie <Unknown> - + <Nieznany/a> %1 users in chat - + %1 użytkowników w czacie @@ -270,19 +273,19 @@ %1 users in chat - + %1 użytkowników w czacie 0 users in chat - + 0 użytkowników w czacie Quit group Menu to quit a groupchat - + Opuść grupę @@ -290,29 +293,29 @@ Public Information - + Informacja publiczna Name Username/nick - + Nick Status Status message - + Status Tox ID - + Tox ID Your Tox ID - + Twój Tox ID @@ -320,47 +323,48 @@ qTox - + qTox Your name - + Twój nick Your status - + Twój status Add friends - + Dodaj znajomych Create a group chat - + Utwórz czat grupowy View completed file transfers - + Zobacz zakończone transfery plików Change your settings - + translated as "change settings"; seems to be simpler this way + Zmień ustawienia Close - + Zamknij Ctrl+Q - + Ctrl+Q @@ -369,7 +373,7 @@ Tox video test Title of the window to test the video/webcam - + Tox test wideo @@ -377,42 +381,42 @@ qTox – Settings - + qTox – Ustawienia General - + Główne Identity - + Tożsamość Privacy - + Prywatność Audio/Video - + Audio/Wideo Ok - + Ok Cancel - + Anuluj Apply - + Zastosuj @@ -421,25 +425,25 @@ Online Button to set your status to 'Online' - + Online Away Button to set your status to 'Away' - + Nieobecny/a Busy Button to set your status to 'Busy' - + Zajęty/a <Unknown> Placeholder when we don't know someone's name in a group chat - + <Nieznany/a> From 4c89233656ef46a30858d80ba6c93b06a20f4369 Mon Sep 17 00:00:00 2001 From: dubslow Date: Sat, 13 Sep 2014 00:55:21 -0500 Subject: [PATCH 020/205] first thing's first, gotta placate the ocd --- mainwindow.ui | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mainwindow.ui b/mainwindow.ui index 7f9cd12c5..20e8269cf 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -3124,13 +3124,13 @@ QSplitter:handle{ 0 - 60 + 57 16777215 - 60 + 57 From 55437df210aaad12710bfe60e81731b0c158be7f Mon Sep 17 00:00:00 2001 From: dubslow Date: Sat, 13 Sep 2014 03:32:24 -0500 Subject: [PATCH 021/205] initial new settings widget, subforms not started also "filing" some files under misc --- core.cpp | 6 +- main.cpp | 2 +- cdata.cpp => misc/cdata.cpp | 0 cdata.h => misc/cdata.h | 0 cstring.cpp => misc/cstring.cpp | 0 cstring.h => misc/cstring.h | 0 settings.cpp => misc/settings.cpp | 0 settings.h => misc/settings.h | 0 smileypack.cpp => misc/smileypack.cpp | 0 smileypack.h => misc/smileypack.h | 0 style.cpp => misc/style.cpp | 0 style.h => misc/style.h | 0 qtox.pro | 24 +-- widget/emoticonswidget.cpp | 4 +- widget/form/genericchatform.cpp | 6 +- widget/form/settingsform.cpp | 142 --------------- widget/form/settingswidget.cpp | 164 ++++++++++++++++++ .../form/{settingsform.h => settingswidget.h} | 35 ++-- widget/groupwidget.cpp | 2 +- widget/tool/chataction.cpp | 2 +- widget/widget.cpp | 32 +--- widget/widget.h | 6 +- 22 files changed, 208 insertions(+), 217 deletions(-) rename cdata.cpp => misc/cdata.cpp (100%) rename cdata.h => misc/cdata.h (100%) rename cstring.cpp => misc/cstring.cpp (100%) rename cstring.h => misc/cstring.h (100%) rename settings.cpp => misc/settings.cpp (100%) rename settings.h => misc/settings.h (100%) rename smileypack.cpp => misc/smileypack.cpp (100%) rename smileypack.h => misc/smileypack.h (100%) rename style.cpp => misc/style.cpp (100%) rename style.h => misc/style.h (100%) delete mode 100644 widget/form/settingsform.cpp create mode 100644 widget/form/settingswidget.cpp rename widget/form/{settingsform.h => settingswidget.h} (60%) diff --git a/core.cpp b/core.cpp index 876301a63..4b081000a 100644 --- a/core.cpp +++ b/core.cpp @@ -15,9 +15,9 @@ */ #include "core.h" -#include "cdata.h" -#include "cstring.h" -#include "settings.h" +#include "misc/cdata.h" +#include "misc/cstring.h" +#include "misc/settings.h" #include "widget/widget.h" #include diff --git a/main.cpp b/main.cpp index 1cdac827e..8e981baa5 100644 --- a/main.cpp +++ b/main.cpp @@ -15,7 +15,7 @@ */ #include "widget/widget.h" -#include "settings.h" +#include "misc/settings.h" #include #include #include diff --git a/cdata.cpp b/misc/cdata.cpp similarity index 100% rename from cdata.cpp rename to misc/cdata.cpp diff --git a/cdata.h b/misc/cdata.h similarity index 100% rename from cdata.h rename to misc/cdata.h diff --git a/cstring.cpp b/misc/cstring.cpp similarity index 100% rename from cstring.cpp rename to misc/cstring.cpp diff --git a/cstring.h b/misc/cstring.h similarity index 100% rename from cstring.h rename to misc/cstring.h diff --git a/settings.cpp b/misc/settings.cpp similarity index 100% rename from settings.cpp rename to misc/settings.cpp diff --git a/settings.h b/misc/settings.h similarity index 100% rename from settings.h rename to misc/settings.h diff --git a/smileypack.cpp b/misc/smileypack.cpp similarity index 100% rename from smileypack.cpp rename to misc/smileypack.cpp diff --git a/smileypack.h b/misc/smileypack.h similarity index 100% rename from smileypack.h rename to misc/smileypack.h diff --git a/style.cpp b/misc/style.cpp similarity index 100% rename from style.cpp rename to misc/style.cpp diff --git a/style.h b/misc/style.h similarity index 100% rename from style.h rename to misc/style.h diff --git a/qtox.pro b/qtox.pro index 7b52d779c..ce7762e79 100644 --- a/qtox.pro +++ b/qtox.pro @@ -79,7 +79,7 @@ win32 { HEADERS += widget/form/addfriendform.h \ widget/form/chatform.h \ widget/form/groupchatform.h \ - widget/form/settingsform.h \ + widget/form/settingswidget.h \ widget/form/filesform.h \ widget/tool/chattextedit.h \ widget/tool/friendrequestdialog.h \ @@ -89,17 +89,17 @@ HEADERS += widget/form/addfriendform.h \ friend.h \ group.h \ grouplist.h \ - settings.h \ + misc/settings.h \ core.h \ friendlist.h \ - cdata.h \ - cstring.h \ + misc/cdata.h \ + misc/cstring.h \ widget/selfcamview.h \ widget/camera.h \ widget/netcamview.h \ - smileypack.h \ + misc/smileypack.h \ widget/emoticonswidget.h \ - style.h \ + misc/style.h \ widget/adjustingscrollarea.h \ widget/croppinglabel.h \ widget/friendlistwidget.h \ @@ -116,7 +116,7 @@ SOURCES += \ widget/form/addfriendform.cpp \ widget/form/chatform.cpp \ widget/form/groupchatform.cpp \ - widget/form/settingsform.cpp \ + widget/form/settingswidget.cpp \ widget/form/filesform.cpp \ widget/tool/chattextedit.cpp \ widget/tool/friendrequestdialog.cpp \ @@ -129,15 +129,15 @@ SOURCES += \ group.cpp \ grouplist.cpp \ main.cpp \ - settings.cpp \ - cdata.cpp \ - cstring.cpp \ + misc/settings.cpp \ + misc/cdata.cpp \ + misc/cstring.cpp \ widget/selfcamview.cpp \ widget/camera.cpp \ widget/netcamview.cpp \ - smileypack.cpp \ + misc/smileypack.cpp \ widget/emoticonswidget.cpp \ - style.cpp \ + misc/style.cpp \ widget/adjustingscrollarea.cpp \ widget/croppinglabel.cpp \ widget/friendlistwidget.cpp \ diff --git a/widget/emoticonswidget.cpp b/widget/emoticonswidget.cpp index bab7abe8d..b0ffb6028 100644 --- a/widget/emoticonswidget.cpp +++ b/widget/emoticonswidget.cpp @@ -15,8 +15,8 @@ */ #include "emoticonswidget.h" -#include "smileypack.h" -#include "style.h" +#include "misc/smileypack.h" +#include "misc/style.h" #include #include diff --git a/widget/form/genericchatform.cpp b/widget/form/genericchatform.cpp index f5681f1c6..2aff5d2a7 100644 --- a/widget/form/genericchatform.cpp +++ b/widget/form/genericchatform.cpp @@ -17,11 +17,11 @@ #include "genericchatform.h" #include "ui_mainwindow.h" #include -#include "smileypack.h" +#include "misc/smileypack.h" #include "widget/emoticonswidget.h" -#include "style.h" +#include "misc/style.h" #include "widget/widget.h" -#include "settings.h" +#include "misc/settings.h" #include "widget/tool/chataction.h" #include "widget/chatareawidget.h" #include "widget/tool/chattextedit.h" diff --git a/widget/form/settingsform.cpp b/widget/form/settingsform.cpp deleted file mode 100644 index 3d4a213da..000000000 --- a/widget/form/settingsform.cpp +++ /dev/null @@ -1,142 +0,0 @@ -/* - Copyright (C) 2014 by Project Tox - - This file is part of qTox, a Qt-based graphical interface for Tox. - - This program 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. - 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 COPYING file for more details. -*/ - -#include "settingsform.h" -#include "widget/widget.h" -#include "settings.h" -#include "smileypack.h" -#include "ui_mainwindow.h" -#include -#include -#include -#include -#include - -SettingsForm::SettingsForm() - : QObject() -{ - main = new QWidget(), head = new QWidget(); - QFont bold, small; - bold.setBold(true); - small.setPixelSize(13); - small.setKerning(false); - headLabel.setText(tr("User Settings","\"Headline\" of the window")); - headLabel.setFont(bold); - - nameLabel.setText(tr("Name","Username/nick")); - statusTextLabel.setText(tr("Status","Status message")); - idLabel.setText("Tox ID " + tr("(click here to copy)", "Click on this text to copy TID to clipboard")); - id.setFont(small); - id.setTextInteractionFlags(Qt::TextSelectableByMouse); - id.setReadOnly(true); - id.setFrameStyle(QFrame::NoFrame); - id.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - id.setFixedHeight(id.document()->size().height()*2); - - videoTest.setText(tr("Test video","Text on a button to test the video/webcam")); - enableIPv6.setText(tr("Enable IPv6 (recommended)","Text on a checkbox to enable IPv6")); - enableIPv6.setChecked(Settings::getInstance().getEnableIPv6()); - useTranslations.setText(tr("Use translations","Text on a checkbox to enable translations")); - useTranslations.setChecked(Settings::getInstance().getUseTranslations()); - makeToxPortable.setText(tr("Make Tox portable","Text on a checkbox to make qTox a portable application")); - makeToxPortable.setChecked(Settings::getInstance().getMakeToxPortable()); - makeToxPortable.setToolTip(tr("Save settings to the working directory instead of the usual conf dir","describes makeToxPortable checkbox")); - - smileyPackLabel.setText(tr("Smiley Pack", "Text on smiley pack label")); - for (auto entry : SmileyPack::listSmileyPacks()) - smileyPackBrowser.addItem(entry.first, entry.second); - smileyPackBrowser.setCurrentIndex(smileyPackBrowser.findData(Settings::getInstance().getSmileyPack())); - - main->setLayout(&layout); - layout.addWidget(&nameLabel); - layout.addWidget(&name); - layout.addWidget(&statusTextLabel); - layout.addWidget(&statusText); - layout.addWidget(&idLabel); - layout.addWidget(&id); - layout.addWidget(&videoTest); - layout.addWidget(&enableIPv6); - layout.addWidget(&useTranslations); - layout.addWidget(&makeToxPortable); - layout.addWidget(&smileyPackLabel); - layout.addWidget(&smileyPackBrowser); - layout.addStretch(); - - head->setLayout(&headLayout); - headLayout.addWidget(&headLabel); - - connect(&videoTest, SIGNAL(clicked()), this, SLOT(onTestVideoClicked())); - connect(&enableIPv6, SIGNAL(stateChanged(int)), this, SLOT(onEnableIPv6Updated())); - connect(&useTranslations, SIGNAL(stateChanged(int)), this, SLOT(onUseTranslationUpdated())); - connect(&makeToxPortable, SIGNAL(stateChanged(int)), this, SLOT(onMakeToxPortableUpdated())); - connect(&idLabel, SIGNAL(clicked()), this, SLOT(copyIdClicked())); - connect(&smileyPackBrowser, SIGNAL(currentIndexChanged(int)), this, SLOT(onSmileyBrowserIndexChanged(int))); -} - -SettingsForm::~SettingsForm() -{ -} - -void SettingsForm::setFriendAddress(const QString& friendAddress) -{ - QString txt{friendAddress}; - txt.insert(38,'\n'); - id.setText(txt); -} - -void SettingsForm::show(Ui::MainWindow &ui) -{ - name.setText(ui.nameLabel->text()); - statusText.setText(ui.statusLabel->text()); - ui.mainContent->layout()->addWidget(main); - ui.mainHead->layout()->addWidget(head); - main->show(); - head->show(); -} - -void SettingsForm::onTestVideoClicked() -{ - Widget::getInstance()->showTestCamview(); -} - -void SettingsForm::onEnableIPv6Updated() -{ - Settings::getInstance().setEnableIPv6(enableIPv6.isChecked()); -} - -void SettingsForm::copyIdClicked() -{ - id.selectAll(); - QString txt = id.toPlainText(); - txt.replace('\n',""); - QApplication::clipboard()->setText(txt); -} - -void SettingsForm::onUseTranslationUpdated() -{ - Settings::getInstance().setUseTranslations(useTranslations.isChecked()); -} - -void SettingsForm::onMakeToxPortableUpdated() -{ - Settings::getInstance().setMakeToxPortable(makeToxPortable.isChecked()); -} - -void SettingsForm::onSmileyBrowserIndexChanged(int index) -{ - QString filename = smileyPackBrowser.itemData(index).toString(); - Settings::getInstance().setSmileyPack(filename); -} diff --git a/widget/form/settingswidget.cpp b/widget/form/settingswidget.cpp new file mode 100644 index 000000000..6e2778de8 --- /dev/null +++ b/widget/form/settingswidget.cpp @@ -0,0 +1,164 @@ +/* + Copyright (C) 2014 by Project Tox + + This file is part of qTox, a Qt-based graphical interface for Tox. + + This program 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. + 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 COPYING file for more details. +*/ + +#include "settingswidget.h" +#include "widget/widget.h" +#include "ui_mainwindow.h" + +SettingsWidget::SettingsWidget() + : QObject() +{ + main = new QWidget(); + // this crap is copied from ui_mainwindow.h... there's no easy way around + // just straight up copying it like this... oh well + // the layout/icons obviously need to be improved, but it's a working model, + // not a pretty one + QSizePolicy sizePolicy3(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); + sizePolicy3.setHorizontalStretch(0); + sizePolicy3.setVerticalStretch(0); + head = new QWidget(); + head->setObjectName(QStringLiteral("head")); + head->setEnabled(true); + sizePolicy3.setHeightForWidth(head->sizePolicy().hasHeightForWidth()); + head->setSizePolicy(sizePolicy3); + QPalette palette5; + QBrush brush(QColor(255, 255, 255, 255)); + brush.setStyle(Qt::SolidPattern); + QBrush brush1(QColor(28, 28, 28, 255)); + brush1.setStyle(Qt::SolidPattern); + QBrush brush2(QColor(42, 42, 42, 255)); + brush2.setStyle(Qt::SolidPattern); + QBrush brush3(QColor(35, 35, 35, 255)); + brush3.setStyle(Qt::SolidPattern); + QBrush brush4(QColor(14, 14, 14, 255)); + brush4.setStyle(Qt::SolidPattern); + QBrush brush5(QColor(18, 18, 18, 255)); + brush5.setStyle(Qt::SolidPattern); + QBrush brush6(QColor(0, 0, 0, 255)); + brush6.setStyle(Qt::SolidPattern); + QBrush brush7(QColor(255, 255, 220, 255)); + brush7.setStyle(Qt::SolidPattern); + palette5.setBrush(QPalette::Active, QPalette::WindowText, brush); + palette5.setBrush(QPalette::Active, QPalette::Button, brush1); + palette5.setBrush(QPalette::Active, QPalette::Light, brush2); + palette5.setBrush(QPalette::Active, QPalette::Midlight, brush3); + palette5.setBrush(QPalette::Active, QPalette::Dark, brush4); + palette5.setBrush(QPalette::Active, QPalette::Mid, brush5); + palette5.setBrush(QPalette::Active, QPalette::Text, brush); + palette5.setBrush(QPalette::Active, QPalette::BrightText, brush); + palette5.setBrush(QPalette::Active, QPalette::ButtonText, brush); + palette5.setBrush(QPalette::Active, QPalette::Base, brush6); + palette5.setBrush(QPalette::Active, QPalette::Window, brush1); + palette5.setBrush(QPalette::Active, QPalette::Shadow, brush6); + palette5.setBrush(QPalette::Active, QPalette::AlternateBase, brush4); + palette5.setBrush(QPalette::Active, QPalette::ToolTipBase, brush7); + palette5.setBrush(QPalette::Active, QPalette::ToolTipText, brush6); + palette5.setBrush(QPalette::Inactive, QPalette::WindowText, brush); + palette5.setBrush(QPalette::Inactive, QPalette::Button, brush1); + palette5.setBrush(QPalette::Inactive, QPalette::Light, brush2); + palette5.setBrush(QPalette::Inactive, QPalette::Midlight, brush3); + palette5.setBrush(QPalette::Inactive, QPalette::Dark, brush4); + palette5.setBrush(QPalette::Inactive, QPalette::Mid, brush5); + palette5.setBrush(QPalette::Inactive, QPalette::Text, brush); + palette5.setBrush(QPalette::Inactive, QPalette::BrightText, brush); + palette5.setBrush(QPalette::Inactive, QPalette::ButtonText, brush); + palette5.setBrush(QPalette::Inactive, QPalette::Base, brush6); + palette5.setBrush(QPalette::Inactive, QPalette::Window, brush1); + palette5.setBrush(QPalette::Inactive, QPalette::Shadow, brush6); + palette5.setBrush(QPalette::Inactive, QPalette::AlternateBase, brush4); + palette5.setBrush(QPalette::Inactive, QPalette::ToolTipBase, brush7); + palette5.setBrush(QPalette::Inactive, QPalette::ToolTipText, brush6); + palette5.setBrush(QPalette::Disabled, QPalette::WindowText, brush4); + palette5.setBrush(QPalette::Disabled, QPalette::Button, brush1); + palette5.setBrush(QPalette::Disabled, QPalette::Light, brush2); + palette5.setBrush(QPalette::Disabled, QPalette::Midlight, brush3); + palette5.setBrush(QPalette::Disabled, QPalette::Dark, brush4); + palette5.setBrush(QPalette::Disabled, QPalette::Mid, brush5); + palette5.setBrush(QPalette::Disabled, QPalette::Text, brush4); + palette5.setBrush(QPalette::Disabled, QPalette::BrightText, brush); + palette5.setBrush(QPalette::Disabled, QPalette::ButtonText, brush4); + palette5.setBrush(QPalette::Disabled, QPalette::Base, brush1); + palette5.setBrush(QPalette::Disabled, QPalette::Window, brush1); + palette5.setBrush(QPalette::Disabled, QPalette::Shadow, brush6); + palette5.setBrush(QPalette::Disabled, QPalette::AlternateBase, brush1); + palette5.setBrush(QPalette::Disabled, QPalette::ToolTipBase, brush7); + palette5.setBrush(QPalette::Disabled, QPalette::ToolTipText, brush6); + head->setPalette(palette5); + head->setAutoFillBackground(true); + iconsLayout = new QHBoxLayout(head); + iconsLayout->setSpacing(0); + iconsLayout->setObjectName(QStringLiteral("iconsLayout")); + iconsLayout->setContentsMargins(0, 0, 0, 0); + + generalButton = new QPushButton(head); + generalButton->setObjectName(QStringLiteral("generalButton")); + generalButton->setMinimumSize(QSize(55, 35)); + generalButton->setMaximumSize(QSize(55, 35)); + generalButton->setFocusPolicy(Qt::NoFocus); + QIcon icon1; + icon1.addFile(QStringLiteral(":/img/add.png"), QSize(), QIcon::Normal, QIcon::Off); + generalButton->setIcon(icon1); + generalButton->setFlat(true); + iconsLayout->addWidget(generalButton); + + identityButton = new QPushButton(head); + identityButton->setObjectName(QStringLiteral("identityButton")); + identityButton->setMinimumSize(QSize(55, 35)); + identityButton->setMaximumSize(QSize(55, 35)); + identityButton->setFocusPolicy(Qt::NoFocus); + QIcon icon2; + icon2.addFile(QStringLiteral(":/img/group.png"), QSize(), QIcon::Normal, QIcon::Off); + identityButton->setIcon(icon2); + identityButton->setFlat(true); + iconsLayout->addWidget(identityButton); + + privacyButton = new QPushButton(head); + privacyButton->setObjectName(QStringLiteral("privacyButton")); + privacyButton->setMinimumSize(QSize(55, 35)); + privacyButton->setMaximumSize(QSize(55, 35)); + privacyButton->setFocusPolicy(Qt::NoFocus); + QIcon icon3; + icon3.addFile(QStringLiteral(":/img/transfer.png"), QSize(), QIcon::Normal, QIcon::Off); + privacyButton->setIcon(icon3); + privacyButton->setFlat(true); + iconsLayout->addWidget(privacyButton); + + avButton = new QPushButton(head); + avButton->setObjectName(QStringLiteral("avButton")); + avButton->setMinimumSize(QSize(55, 35)); + avButton->setMaximumSize(QSize(55, 35)); + avButton->setFocusPolicy(Qt::NoFocus); + QIcon icon4; + icon4.addFile(QStringLiteral(":/img/settings.png"), QSize(), QIcon::Normal, QIcon::Off); + avButton->setIcon(icon4); + avButton->setFlat(true); + iconsLayout->addWidget(avButton); + + head->setLayout(iconsLayout); + +} + +SettingsWidget::~SettingsWidget() +{ +} + +void SettingsWidget::show(Ui::MainWindow& ui) +{ + ui.mainContent->layout()->addWidget(main); + ui.mainHead->layout()->addWidget(head); + main->show(); + head->show(); +} diff --git a/widget/form/settingsform.h b/widget/form/settingswidget.h similarity index 60% rename from widget/form/settingsform.h rename to widget/form/settingswidget.h index a081d01fb..a1cee909f 100644 --- a/widget/form/settingsform.h +++ b/widget/form/settingswidget.h @@ -14,8 +14,8 @@ See the COPYING file for more details. */ -#ifndef SETTINGSFORM_H -#define SETTINGSFORM_H +#ifndef SETTINGSWIDGET_H +#define SETTINGSWIDGET_H #include #include @@ -31,37 +31,32 @@ namespace Ui {class MainWindow;} class QString; -class SettingsForm : public QObject +class SettingsWidget : public QObject { Q_OBJECT public: - SettingsForm(); - ~SettingsForm(); + SettingsWidget(); + ~SettingsWidget(); void show(Ui::MainWindow &ui); public slots: - void setFriendAddress(const QString& friendAddress); + //void setFriendAddress(const QString& friendAddress); private slots: - void onTestVideoClicked(); - void onEnableIPv6Updated(); - void onUseTranslationUpdated(); - void onMakeToxPortableUpdated(); - void onSmileyBrowserIndexChanged(int index); - void copyIdClicked(); private: - QLabel headLabel, nameLabel, statusTextLabel, smileyPackLabel; - QTextEdit id; - CroppingLabel idLabel; - QPushButton videoTest; - QCheckBox enableIPv6, useTranslations, makeToxPortable; - QVBoxLayout layout, headLayout; QWidget *main, *head; - QComboBox smileyPackBrowser; + // the code pertaining to the icons is mostly copied from ui_mainwindow.h + QHBoxLayout *iconsLayout; + QPushButton *generalButton; + QPushButton *identityButton; + QPushButton *privacyButton; + QPushButton *avButton; + + // now the actual pages and stuff + // ... public: - QLineEdit name, statusText; }; #endif // SETTINGSFORM_H diff --git a/widget/groupwidget.cpp b/widget/groupwidget.cpp index b8c1cbcc0..0c02db3d2 100644 --- a/widget/groupwidget.cpp +++ b/widget/groupwidget.cpp @@ -17,7 +17,7 @@ #include "groupwidget.h" #include "grouplist.h" #include "group.h" -#include "settings.h" +#include "misc/settings.h" #include "widget/form/groupchatform.h" #include #include diff --git a/widget/tool/chataction.cpp b/widget/tool/chataction.cpp index 0847abdda..dacde43ee 100644 --- a/widget/tool/chataction.cpp +++ b/widget/tool/chataction.cpp @@ -15,7 +15,7 @@ */ #include "chataction.h" -#include "smileypack.h" +#include "misc/smileypack.h" #include #include #include "filetransferinstance.h" diff --git a/widget/widget.cpp b/widget/widget.cpp index abe14460a..29aef03be 100644 --- a/widget/widget.cpp +++ b/widget/widget.cpp @@ -17,7 +17,7 @@ #include "widget.h" #include "ui_mainwindow.h" #include "core.h" -#include "settings.h" +#include "misc/settings.h" #include "friend.h" #include "friendlist.h" #include "widget/tool/friendrequestdialog.h" @@ -26,7 +26,7 @@ #include "group.h" #include "widget/groupwidget.h" #include "widget/form/groupchatform.h" -#include "style.h" +#include "misc/style.h" #include "selfcamview.h" #include "widget/friendlistwidget.h" #include "camera.h" @@ -179,7 +179,7 @@ Widget::Widget(QWidget *parent) connect(core, &Core::statusSet, this, &Widget::onStatusSet); connect(core, &Core::usernameSet, this, &Widget::setUsername); connect(core, &Core::statusMessageSet, this, &Widget::setStatusMessage); - connect(core, &Core::friendAddressGenerated, &settingsForm, &SettingsForm::setFriendAddress); + //connect(core, &Core::friendAddressGenerated, &settingsWidget, &SettingsWidget::setFriendAddress); connect(core, SIGNAL(fileDownloadFinished(const QString&)), &filesForm, SLOT(onFileDownloadComplete(const QString&))); connect(core, SIGNAL(fileUploadFinished(const QString&)), &filesForm, SLOT(onFileUploadComplete(const QString&))); connect(core, &Core::friendAdded, this, &Widget::addFriend); @@ -210,8 +210,6 @@ Widget::Widget(QWidget *parent) connect(setStatusOnline, SIGNAL(triggered()), this, SLOT(setStatusOnline())); connect(setStatusAway, SIGNAL(triggered()), this, SLOT(setStatusAway())); connect(setStatusBusy, SIGNAL(triggered()), this, SLOT(setStatusBusy())); - connect(&settingsForm.name, SIGNAL(editingFinished()), this, SLOT(onUsernameChanged())); - connect(&settingsForm.statusText, SIGNAL(editingFinished()), this, SLOT(onStatusMessageChanged())); connect(&friendForm, SIGNAL(friendRequested(QString,QString)), this, SIGNAL(friendRequested(QString,QString))); coreThread->start(); @@ -339,7 +337,7 @@ void Widget::onTransferClicked() void Widget::onSettingsClicked() { hideMainForms(); - settingsForm.show(*ui); + settingsWidget.show(*ui); activeChatroomWidget = nullptr; } @@ -357,20 +355,10 @@ void Widget::hideMainForms() } } -void Widget::onUsernameChanged() -{ - const QString newUsername = settingsForm.name.text(); - ui->nameLabel->setText(newUsername); - ui->nameLabel->setToolTip(newUsername); // for overlength names - settingsForm.name.setText(newUsername); - core->setUsername(newUsername); -} - void Widget::onUsernameChanged(const QString& newUsername, const QString& oldUsername) { ui->nameLabel->setText(oldUsername); // restore old username until Core tells us to set it ui->nameLabel->setToolTip(oldUsername); // for overlength names - settingsForm.name.setText(oldUsername); core->setUsername(newUsername); } @@ -378,23 +366,12 @@ void Widget::setUsername(const QString& username) { ui->nameLabel->setText(username); ui->nameLabel->setToolTip(username); // for overlength names - settingsForm.name.setText(username); -} - -void Widget::onStatusMessageChanged() -{ - const QString newStatusMessage = settingsForm.statusText.text(); - ui->statusLabel->setText(newStatusMessage); - ui->statusLabel->setToolTip(newStatusMessage); // for overlength messsages - settingsForm.statusText.setText(newStatusMessage); - core->setStatusMessage(newStatusMessage); } void Widget::onStatusMessageChanged(const QString& newStatusMessage, const QString& oldStatusMessage) { ui->statusLabel->setText(oldStatusMessage); // restore old status message until Core tells us to set it ui->statusLabel->setToolTip(oldStatusMessage); // for overlength messsages - settingsForm.statusText.setText(oldStatusMessage); core->setStatusMessage(newStatusMessage); } @@ -402,7 +379,6 @@ void Widget::setStatusMessage(const QString &statusMessage) { ui->statusLabel->setText(statusMessage); ui->statusLabel->setToolTip(statusMessage); // for overlength messsages - settingsForm.statusText.setText(statusMessage); } void Widget::addFriend(int friendId, const QString &userId) diff --git a/widget/widget.h b/widget/widget.h index 1fbecb412..ec054863c 100644 --- a/widget/widget.h +++ b/widget/widget.h @@ -19,7 +19,7 @@ #include #include "widget/form/addfriendform.h" -#include "widget/form/settingsform.h" +#include "widget/form/settingswidget.h" #include "widget/form/filesform.h" #include "corestructs.h" @@ -83,8 +83,6 @@ private slots: void onFailedToStartCore(); void onUsernameChanged(const QString& newUsername, const QString& oldUsername); void onStatusMessageChanged(const QString& newStatusMessage, const QString& oldStatusMessage); - void onUsernameChanged(); - void onStatusMessageChanged(); void setUsername(const QString& username); void setStatusMessage(const QString &statusMessage); void addFriend(int friendId, const QString& userId); @@ -137,7 +135,7 @@ private: Core* core; QThread* coreThread; AddFriendForm friendForm; - SettingsForm settingsForm; + SettingsWidget settingsWidget; FilesForm filesForm; static Widget* instance; GenericChatroomWidget* activeChatroomWidget; From 5e12a5fa3e14c3c2c80a619ffa69875a49894ea6 Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Sat, 13 Sep 2014 11:49:58 +0200 Subject: [PATCH 022/205] Update translations --- qtox.pro | 2 +- translations/de.qm | Bin 4328 -> 3969 bytes translations/fr.qm | Bin 4515 -> 3969 bytes translations/it.qm | Bin 5964 -> 5820 bytes translations/pl.qm | Bin 0 -> 6709 bytes translations/ru.qm | Bin 6821 -> 6581 bytes 6 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 translations/pl.qm diff --git a/qtox.pro b/qtox.pro index b733387b8..250d3abc8 100644 --- a/qtox.pro +++ b/qtox.pro @@ -33,7 +33,7 @@ TRANSLATIONS = translations/de.ts \ translations/fr.ts \ translations/it.ts \ translations/ru.ts \ - translations/po.ts \ + translations/pl.ts \ translations/mannol.ts RESOURCES += res.qrc diff --git a/translations/de.qm b/translations/de.qm index c5132443ed394bc90ef30d8bba13ec0870e60e15..8a6769d20ef422e9932aed64235f71b97cd1ba2b 100644 GIT binary patch delta 731 zcmZWlOK1~O6g|_tnM^Wordh-ytwkzrt=3kNRumT{!G2X*Yqh!&V=_qx!$gv)F@nUP zg-8{JQCr&LDhsX97AguVC{&?z;No)LIq%$i&wHP0GV8B- z(|ur9E&*y9Z0Zi-48*QhKuMtGHv_~k@D1C5V*x!oZUDT((OvZmka`?TVSDAFk}w0FFS&xSn-A1e{6NJC%|-pSXYCYynt5 z?`)t!{G1w^J4MO4y13yhy%_4!B~t<8n+k$>3$G|&85!7JK| z+(D(;6Y}OY-VP(G55xmzBCN-|&4d*&gZlhyS#j7S+A*$l>ZTqKMEe2}-TuJ$%H;*Y z2-?kjryWx(?FPPJ@8*qkUbMe!TX=U!H!Z_T6*`*AHT}I8{1yZjWHB5c=iY#4~3Bn&H C;=F4B delta 1043 zcmZuuTSyd982-ndnVp^88O;nummJHrNV5bDe5fcdS&EUaMFiF8p1tJm&N6d$b$eN) z3xY+)R7y$@B|X%G!dg%i6;_0AQEx#7f%a}UBBFnGRkUI_^WVSk`_CCD{aiL&kU9x) zEC?XK2KIImfPVvAOC5mJ2NlmYVtxzM{$>H}w_s1)1hCD(fgM*duiN&Q`~(mf+w90W z0C>SB$0_!mU`Ge90Ei@OoiEwz^%%R{?A=QY&P}kBB}Wn8&OR#t0+7nN!G0h6gaC&) z&(`+<&MIzqupEE^?t*gy2|BntLo+xq&E21PivsrYy~R%vP~$aM6AHe_YmHqx|fE=g$D-Rtn6(S;YS)q}pym5V$$lb0owc*J=US4%fcTNFaZed{Z&Z&q#FoG62^uz1pyV!a!N}Tp#j@skv6T}Vf+{uR{6SkDw3@pdg>JS%izThLe9KY0!=x!3@{u;Rn}p3L z{LX^4&7m;y>T1;R6P+Fj`2vKd*Vvu5^qeR#=8)K&e&^&FlgRC+TRbkgItitrXuxPj zrRGPW&|Gj8=dVm=uH9vBm)EW5JE=!3!GnFTaG%tMyw5OZ{`w Sw&htxuFGAT9mJj-hWP`r)cl74 diff --git a/translations/fr.qm b/translations/fr.qm index e3d68b2e1a1bf5114c201fee7de16d73986ac815..98e9e1aaa0abc0d733d08a78db17bff6152751da 100644 GIT binary patch delta 603 zcmZ3i+$cXmq&|RwrMHuTfw!80WzI?0|~5=GP2f zW>Xm$c;uKprGEj%)0j_9Z)IR$IL}f!r-Xrl^#;p~jwuWboM#|3*A|vpmOwt&AC}eq zj6i*UEbFBs85lSoubdV8*=6=nVEp-4W?#PzU160qd!qeT_&I95uRMnGY^PmC;#VVoxG2C z`($l?DIU+1)Vz|+l1i|yKz?;0WC2EIpi6ls7qW;>zQ@ANi>kO%K$V-zH!(9WJTosP zzkKpi0W}o9x}ZJ^KUUBjgK>nR{9Y35 zqJ1qyVTK&X#wz!RQ`tt{)Q?$7?I}-)vi7Z z{F7(v{9i=Ah-Yl@2ob&FyM`U)4e~>MXNUq9GrJ`6=hh*X>iC-{IigfJm%lxK4+<>j z9~XWjnl;4#IR733JA}xJw?x5Op`xXbh!X{^q#8ymh2z1iC^R74IQ9&@QQ`j8*Dz8h zw&jgNn2Dx@Jn^1rZmNfYwPM%qeB@1fxp}UU&)z^}5ceC>dy0a+-m#B|A^g(Eb@!mq zS6^!TWg?;2-!~jZ-0Oe769=a1Bfzb(_Xf_wP+sc&)DTS)Z!qTV%Z-rtw zDbz$NwbN%Hs?Svv@dT^XcFj^1%`z>oi)CWYgYzM(Arsl{;5pz&s5Gl(0GpwRD1qz* zb~}Z#Ni3J_pkOgT9WpLrW9igLM%q%wm_bEgIKT}&Hg2q}!SX4Canov79VJq#Buq!K zJCaG$aP)Y~SDDE! zmo(QssEvkJZRjy=yV|H3?47tRH>XB7w5X*f?6_t*4SK9ubM97pWe@8KE@Tx_9vctl zu=O}!3U;%H0b?p&!!Ag3SgX{}^iVCU3+$DpU7F+QiDtV79kK6H{!C!8T+}u_BmE^7 zQ51G0s`ndRw!U ze>MN(u@51g9hVianCY55ke9N`@VWx`7ZG91q|U4XPt@#8&weWRle{v^TM}9mp3>m@ Jz@6pc{sJaL3BUjV diff --git a/translations/it.qm b/translations/it.qm index 890aaaea2f5951d4070983c7a9ca61a7acc417b1..2523c49cbbb5ce0bc93e6891af285cbe0d984d2e 100644 GIT binary patch delta 568 zcmX@3w?}t^NZ<(umflVV1`#g?mN_edbU6d7hbaStz!C=b>4YFl#OFqFCEFi!2O(MkIEMY2BsA(-)BE&U|{fPRn@%*R9^<6MR-`v zy%sYt@UgJkXQ(hRF!Hdb8n^;ow~V!idkF&r=N;Bn-G_nZUS!?21n3H8C@sjumMwLF zL7PD!hAp25sDbq$TfR#u0|T2cJEH{1LEP+Is?&i6N3frI-VF4f|72T6yLw?!p5kzz zJ2={S-mC9sVBkH@o3fz*=uUUu6H1qXzBL8XpMmaV;5{`PXdIUWpNzf|(AR7EWM-rQ z)y?EHo*xIaW-4D$0Wg#V8~K8|*8@X~l`mKZsGoz8Z$sJ^pmhf_fu6X`3^YiI!I2>y z2s0T<87AuraBOB`y39Q}Ryc--+dVZewJ0$sATd34@-bmw6oJjYB7BS}B9k*j4N(OY z#5_<0HecWkWSXohBE#dElA2eNSyBl$dYPyys=zK*HC_~v%`yUam?nSbGh$~8&rC^A KEt$MqY$5;?5tuXp delta 761 zcmZXQOH30{6o&sPbK6>GZcAHCBaPHb5kf!=R^kRjB8ZJd1EL`s6{jN|3r=kdhK*eq zjRp`&MUj%QkOk@jVvQToNZb(O!dK!#Wn&Br6HR=?m5_9X%F8UowK0KSaW z&sTtzW9ldairyKlCl&f19#zW|QnNUI@hTt(#EI>hI4Ry45vY1toGs}jwJy$=eFF?L z;*ZpO0DGCQdYN>L)dz0U)_S%hR0aqVQ)`=m;uEiUff?4{cZa`$+UbT@e2 z)Dc=Y#@ixvOFY5b250HE7;kq|zgggOC+^X@M;e(qR6v8gXhb(14Sh&|5#AK08*F)YQdFSRw??%nWh%`XG$TFE3Z+L=!k&;CRXuUt zqv(-=N)r{Nb~PT?PIbqc^=NN$QSOp+Gk)HhmpO0WkRwT7=3L0r%viVNW$xO29sjQq zGG5nXA93pF&wA;}zRwW%@vOVvfAp69YAo*Q*Mh3Pn)!pZr8oyDJKBZa$+M2qQn@3h OMm>KwukNl|JNgF{>BDpY diff --git a/translations/pl.qm b/translations/pl.qm new file mode 100644 index 0000000000000000000000000000000000000000..d05682dd157ed6c4cdf4f6a3a40d7171139dab1b GIT binary patch literal 6709 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 sz?J0#d8cMMAJtQa6z>Ee2UAMVk*( zPXOZTCE_wfavUhPLk1fFcQw>-H&A*F_5TE5T}0rcA8@QiQ(qJiyAV7Z0Lm1!Y`O`Q zd`0^=&KYG${9OW8RbljyB)`urnx2r?Xm*}B%KNn9DNF$oKnYd;0ko}3HZ}m5%*xx5 zA2f1`{^S|rh=_;gIXEEVgEuJrvxqLIxD(*nbyD2FZlYknn5f(j*dK^_UjZ<$h+l~> z0B*_J4W9sKu85wL+}v`HI?Zxhw~zj&MtQ7m2OHPREA|wF+?MH~XKbF74^vBwmn)+C zwajN|SYoz>*F2?h-qPdXoJ?AJwzmP6cGXnDcW0YwtBuj%t~&hkH#d4j&8}SF26tOc z=Poi>NYhU(Qa_{(CinW-_=UC*oCR!QEk8a+!Da2U&IYzQ+wj&mo66)IJWDp5DpVUEeE^H!@n`eF5} E|6D7NYXATM delta 770 zcmX9+Ye-XJ7=E^WXJ?x`XKGWInjJ;4z-T#_m&}?Ox@81flqJe=n=Z|nmqPk6A_c=D zaix;RgcP#K3tB%)NXXJg`9n?UM;D3`vIt7LV)Uj54iE3;d7tOJ@3~{@H@E4%X#jT& z2!8^0@jMVQ0oF4>xCAcG41^4VudD#VVvzEe0qPQ@zcc~b5m*|00Nane)9FOeFb)1Zbv96ZOfUbEBgZ=DkI>o^&?A9e2pjWe@s3J0$ z#m3{80r?{P(fy9bcW?F7+T6LOp{<}yRtHJf;Qw*dbGq-CMi8RhX_CNG6U6h?|Dr^C!vvV zoBBn@zw&{_b7b(1N_Mu1j9Jyf$r&#Vc%g3TIY Date: Sat, 13 Sep 2014 14:00:37 +0200 Subject: [PATCH 023/205] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d6358283e..dd7c45fdb 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ However, it is not a fork. - Group chats - File transfers, with previewing of images - Audio calls -- Video calls (alpha) +- Video calls - Tox DNS - Translations in various languages From 54ab54543465aca7948f1c3fae9519b90007d0dd Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Sat, 13 Sep 2014 15:03:41 +0200 Subject: [PATCH 024/205] Embed new translations --- res.qrc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/res.qrc b/res.qrc index 6a121b0ad..f258db6f5 100644 --- a/res.qrc +++ b/res.qrc @@ -139,5 +139,7 @@ img/settings/identity.png img/settings/privacy.png img/settings/av.png + translations/pl.qm + translations/mannol.qm From 41261c5379975bc6577c79bfd36e4c9565fca6ef Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Sat, 13 Sep 2014 15:15:35 +0200 Subject: [PATCH 025/205] Update translations --- translations/de.ts | 55 ++++++++++++++++++++++--------------- translations/fr.ts | 55 ++++++++++++++++++++++--------------- translations/it.ts | 55 ++++++++++++++++++++++--------------- translations/mannol.ts | 55 ++++++++++++++++++++++--------------- translations/pl.ts | 57 ++++++++++++++++++++++++--------------- translations/ru.ts | 55 ++++++++++++++++++++++--------------- widget/settingsdialog.cpp | 8 +++--- 7 files changed, 210 insertions(+), 130 deletions(-) diff --git a/translations/de.ts b/translations/de.ts index 42adc68f9..f8b790182 100644 --- a/translations/de.ts +++ b/translations/de.ts @@ -4,10 +4,23 @@ AVPage - + Video Settings + + + + Show video preview + On a button + + + + + Hide video preview + On a button + + AddFriendForm @@ -227,41 +240,41 @@ GeneralPage - + General Settings - + Enable IPv6 (recommended) Text on a checkbox to enable IPv6 IPv6 aktivieren (empfohlen) - + Use translations Text on a checkbox to enable translations - + Make Tox portable Text on a checkbox to make qTox a portable application - + Save settings to the working directory instead of the usual conf dir describes makeToxPortable checkbox - + Theme - + Smiley Pack @@ -322,29 +335,29 @@ IdentityPage - + Public Information - + Name Username/nick Benutzername - + Status Status message Status - + Tox ID Tox ID - + Your Tox ID @@ -409,42 +422,42 @@ SettingsDialog - + qTox – Settings - + General - + Identity - + Privacy - + Audio/Video - + Ok - + Cancel - + Apply diff --git a/translations/fr.ts b/translations/fr.ts index 2f61287cb..53b39e179 100644 --- a/translations/fr.ts +++ b/translations/fr.ts @@ -4,10 +4,23 @@ AVPage - + Video Settings + + + + Show video preview + On a button + + + + + Hide video preview + On a button + + AddFriendForm @@ -227,41 +240,41 @@ GeneralPage - + General Settings - + Enable IPv6 (recommended) Text on a checkbox to enable IPv6 Activer IPv6 (recommandé) - + Use translations Text on a checkbox to enable translations - + Make Tox portable Text on a checkbox to make qTox a portable application - + Save settings to the working directory instead of the usual conf dir describes makeToxPortable checkbox - + Theme - + Smiley Pack @@ -322,29 +335,29 @@ IdentityPage - + Public Information - + Name Username/nick Nom - + Status Status message Status - + Tox ID ID Tox - + Your Tox ID @@ -409,42 +422,42 @@ SettingsDialog - + qTox – Settings - + General - + Identity - + Privacy - + Audio/Video - + Ok - + Cancel - + Apply diff --git a/translations/it.ts b/translations/it.ts index a7c3f39c0..35b4c928d 100644 --- a/translations/it.ts +++ b/translations/it.ts @@ -4,10 +4,23 @@ AVPage - + Video Settings + + + + Show video preview + On a button + + + + + Hide video preview + On a button + + AddFriendForm @@ -197,41 +210,41 @@ GeneralPage - + General Settings - + Enable IPv6 (recommended) Text on a checkbox to enable IPv6 Abilita IPv6 (consigliato) - + Use translations Text on a checkbox to enable translations Abilita traduzioni - + Make Tox portable Text on a checkbox to make qTox a portable application Rendi qTox portabile - + Save settings to the working directory instead of the usual conf dir describes makeToxPortable checkbox Slava le impostazioni nella directory di lavoro corrente, invece della directory di default - + Theme - + Smiley Pack Emoticons @@ -288,29 +301,29 @@ IdentityPage - + Public Information - + Name Username/nick Nome - + Status Status message Stato - + Tox ID Tox ID - + Your Tox ID @@ -375,42 +388,42 @@ SettingsDialog - + qTox – Settings - + General - + Identity - + Privacy - + Audio/Video - + Ok - + Cancel - + Apply diff --git a/translations/mannol.ts b/translations/mannol.ts index a1856348e..ccc08ff82 100644 --- a/translations/mannol.ts +++ b/translations/mannol.ts @@ -4,10 +4,23 @@ AVPage - + Video Settings + + + + Show video preview + On a button + + + + + Hide video preview + On a button + + AddFriendForm @@ -197,41 +210,41 @@ GeneralPage - + General Settings - + Enable IPv6 (recommended) Text on a checkbox to enable IPv6 - + Use translations Text on a checkbox to enable translations - + Make Tox portable Text on a checkbox to make qTox a portable application - + Save settings to the working directory instead of the usual conf dir describes makeToxPortable checkbox - + Theme - + Smiley Pack @@ -288,29 +301,29 @@ IdentityPage - + Public Information - + Name Username/nick - + Status Status message - + Tox ID - + Your Tox ID @@ -375,42 +388,42 @@ SettingsDialog - + qTox – Settings - + General - + Identity - + Privacy - + Audio/Video - + Ok - + Cancel - + Apply diff --git a/translations/pl.ts b/translations/pl.ts index 6aaa4e6d6..edff773c3 100644 --- a/translations/pl.ts +++ b/translations/pl.ts @@ -1,13 +1,26 @@ - + AVPage - + Video Settings Ustawienia wideo + + + + Show video preview + On a button + + + + + Hide video preview + On a button + + AddFriendForm @@ -199,41 +212,41 @@ GeneralPage - + General Settings Główne ustawienia - + Enable IPv6 (recommended) Text on a checkbox to enable IPv6 Użyj IPv6 (rekomendowane) - + Use translations Text on a checkbox to enable translations Użyj tłumaczenia - + Make Tox portable Text on a checkbox to make qTox a portable application Zrób Tox przenośnym - + Save settings to the working directory instead of the usual conf dir describes makeToxPortable checkbox Zamiast domyślnego katalogu użyj obecnego do zapisania ustawień - + Theme Motyw - + Smiley Pack needs better translation Paczka uśmiechów @@ -291,29 +304,29 @@ IdentityPage - + Public Information Informacja publiczna - + Name Username/nick Nick - + Status Status message Status - + Tox ID Tox ID - + Your Tox ID Twój Tox ID @@ -379,42 +392,42 @@ SettingsDialog - + qTox – Settings qTox – Ustawienia - + General Główne - + Identity Tożsamość - + Privacy Prywatność - + Audio/Video Audio/Wideo - + Ok Ok - + Cancel Anuluj - + Apply Zastosuj diff --git a/translations/ru.ts b/translations/ru.ts index 87c52b238..56c4aaebf 100644 --- a/translations/ru.ts +++ b/translations/ru.ts @@ -4,10 +4,23 @@ AVPage - + Video Settings Настройки видео + + + + Show video preview + On a button + + + + + Hide video preview + On a button + + AddFriendForm @@ -246,41 +259,41 @@ GeneralPage - + General Settings Основные настройки - + Enable IPv6 (recommended) Text on a checkbox to enable IPv6 Включить IPv6 (рекомендуется) - + Use translations Text on a checkbox to enable translations Русскоязычный интерфейс - + Make Tox portable Text on a checkbox to make qTox a portable application Портативный режим - + Save settings to the working directory instead of the usual conf dir describes makeToxPortable checkbox Сохранять настройки в рабочую директорию вместо страндартной директории настроек - + Theme Тема - + Smiley Pack Набор смайликов @@ -341,29 +354,29 @@ IdentityPage - + Public Information Публичные данные - + Name Username/nick Имя - + Status Status message Статус - + Tox ID Tox ID - + Your Tox ID Ваш Tox ID @@ -432,42 +445,42 @@ Диалог настроек - + qTox – Settings - + General Основное - + Identity Личные данные - + Privacy Безопасность - + Audio/Video Аудио и видео - + Ok ОК - + Cancel Отмена - + Apply Применить diff --git a/widget/settingsdialog.cpp b/widget/settingsdialog.cpp index 05ce3c165..d81973286 100644 --- a/widget/settingsdialog.cpp +++ b/widget/settingsdialog.cpp @@ -23,6 +23,7 @@ //======================================== class GeneralPage : public QWidget { + Q_OBJECT public: GeneralPage(QWidget *parent = 0) : QWidget(parent) @@ -72,6 +73,7 @@ public: class IdentityPage : public QWidget { + Q_OBJECT public: IdentityPage(QWidget* parent = 0) : QWidget(parent) @@ -131,7 +133,7 @@ public: camView = new SelfCamView(parent->getWidget()->getCamera()); camView->hide(); // hide by default - testVideo = new QPushButton("Show video preview"); + testVideo = new QPushButton(tr("Show video preview","On a button")); connect(testVideo, SIGNAL(clicked()), this, SLOT(onTestVideoPressed())); QVBoxLayout *vLayout = new QVBoxLayout(); @@ -152,13 +154,13 @@ public: void showTestVideo() { - testVideo->setText("Hide video preview"); + testVideo->setText(tr("Hide video preview","On a button")); camView->show(); } void closeTestVideo() { - testVideo->setText("Show video preview"); + testVideo->setText(tr("Show video preview","On a button")); camView->close(); } From 1225a513c7cca7ff8aee5a52883331de76b55e34 Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Sat, 13 Sep 2014 15:24:53 +0200 Subject: [PATCH 026/205] Update French translation --- translations/fr.qm | Bin 3969 -> 7085 bytes translations/fr.ts | 90 ++++++++++++++++++++++----------------------- 2 files changed, 45 insertions(+), 45 deletions(-) diff --git a/translations/fr.qm b/translations/fr.qm index 98e9e1aaa0abc0d733d08a78db17bff6152751da..278415266881501d4faa330eddeeb5386c01c6cc 100644 GIT binary patch literal 7085 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 MyiLMq@ Video Settings - + Options vidéo Show video preview On a button - + Montrer l'aperçu vidéo Hide video preview On a button - + Cacher l'aperçu vidéo @@ -62,13 +62,13 @@ You can't add yourself as a friend! When trying to add your own Tox ID as friend - + Vous ne pouvez pas vous ajouter vous même en temps qu'ami! This address does not exist The DNS gives the Tox ID associated to toxme.se addresses - + Cette addresse n'existe pas @@ -138,19 +138,19 @@ Save a file Title of the file saving dialog - Sauvegarder un fichier + Sauvegarder un fichier Location not writable Title of permissions popup - + Impossible d'écrire ici You do not have permission to write that location. Choose another, or cancel the save dialog. text of permissions popup - + Vous n'avez pas la permission d'écrire ici. Choisissez un audre endroit, ou annulez. @@ -167,17 +167,17 @@ Transfered Files "Headline" of the window - + Transfers Downloads - + Téléchargements Uploads - + Envois @@ -242,41 +242,41 @@ General Settings - + Options Générales Enable IPv6 (recommended) Text on a checkbox to enable IPv6 - Activer IPv6 (recommandé) + Activer IPv6 (recommandé) Use translations Text on a checkbox to enable translations - + Utiliser les traductions Make Tox portable Text on a checkbox to make qTox a portable application - + Rendre Tox portable Save settings to the working directory instead of the usual conf dir describes makeToxPortable checkbox - + Sauvegarde les options dans le dossier courant au lieu du dossier de configuration habituel Theme - + Thème Smiley Pack - + Pack de smileys @@ -285,7 +285,7 @@ Save chat log - Sauvegarder l'historique de conversation + Sauvegarder l'historique de conversation @@ -337,29 +337,29 @@ Public Information - + Informations Publiques Name Username/nick - Nom + Nom Status Status message - Status + Status Tox ID - ID Tox + ID Tox Your Tox ID - + Votre ID Tox @@ -367,47 +367,47 @@ qTox - + qTox Your name - Votre nom + Votre nom Your status - Votre status + Votre status Add friends - + Ajouter des amis Create a group chat - + Creer un groupe View completed file transfers - + Voir les transfers de fichiers terminés Change your settings - + Changer les options Close - Fermer + Fermer Ctrl+Q - Ctrl+Q + Ctrl+Q @@ -424,42 +424,42 @@ qTox – Settings - + qTox — Options General - + General Identity - + Identité Privacy - + Vie Privée Audio/Video - + Audio/Vidéo Ok - + Ok Cancel - + Annuler Apply - + Appliquer @@ -516,25 +516,25 @@ Online Button to set your status to 'Online' - Connecté + Connecté Away Button to set your status to 'Away' - Indisponnible + Indisponnible Busy Button to set your status to 'Busy' - Occupé + Occupé <Unknown> Placeholder when we don't know someone's name in a group chat - <Inconnu> + <Inconnu> From aaecc9ba7c46c5ca9ed21421a5825c4c2405fede Mon Sep 17 00:00:00 2001 From: Zetok Zalbavar Date: Sat, 13 Sep 2014 16:38:50 +0100 Subject: [PATCH 027/205] Update Polish translation --- translations/pl.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/translations/pl.ts b/translations/pl.ts index edff773c3..481762e0e 100644 --- a/translations/pl.ts +++ b/translations/pl.ts @@ -13,13 +13,13 @@ Show video preview On a button - + Pokaż podgląd wideo Hide video preview On a button - + Ukryj podgląd wideo From 741824c019604a919f958bf9443055b7c099c085 Mon Sep 17 00:00:00 2001 From: bill Date: Sun, 14 Sep 2014 13:42:27 -0500 Subject: [PATCH 028/205] move buttons to bottom --- widget/form/settingswidget.cpp | 66 +++++++++++++++++++--------------- widget/form/settingswidget.h | 20 +++++------ 2 files changed, 48 insertions(+), 38 deletions(-) diff --git a/widget/form/settingswidget.cpp b/widget/form/settingswidget.cpp index 6e2778de8..fcbd2a981 100644 --- a/widget/form/settingswidget.cpp +++ b/widget/form/settingswidget.cpp @@ -19,9 +19,35 @@ #include "ui_mainwindow.h" SettingsWidget::SettingsWidget() - : QObject() + : QWidget() { + _main = new QWidget(); main = new QWidget(); + head = new QWidget(); + foot = new QWidget(); + prepButtons(); + foot->setLayout(iconsLayout); + _mainLayout = new QVBoxLayout(_main); + _mainLayout->addWidget(main); + _mainLayout->addWidget(foot); + // something something foot size + _main->setLayout(_mainLayout); +} + +SettingsWidget::~SettingsWidget() +{ +} + +void SettingsWidget::show(Ui::MainWindow& ui) +{ + ui.mainContent->layout()->addWidget(_main); + ui.mainHead->layout()->addWidget(head); + _main->show(); + head->show(); +} + +void SettingsWidget::prepButtons() +{ // this crap is copied from ui_mainwindow.h... there's no easy way around // just straight up copying it like this... oh well // the layout/icons obviously need to be improved, but it's a working model, @@ -29,11 +55,9 @@ SettingsWidget::SettingsWidget() QSizePolicy sizePolicy3(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); sizePolicy3.setHorizontalStretch(0); sizePolicy3.setVerticalStretch(0); - head = new QWidget(); - head->setObjectName(QStringLiteral("head")); - head->setEnabled(true); - sizePolicy3.setHeightForWidth(head->sizePolicy().hasHeightForWidth()); - head->setSizePolicy(sizePolicy3); + foot->setObjectName(QStringLiteral("foot")); + foot->setEnabled(true); + foot->setSizePolicy(sizePolicy3); QPalette palette5; QBrush brush(QColor(255, 255, 255, 255)); brush.setStyle(Qt::SolidPattern); @@ -96,14 +120,15 @@ SettingsWidget::SettingsWidget() palette5.setBrush(QPalette::Disabled, QPalette::AlternateBase, brush1); palette5.setBrush(QPalette::Disabled, QPalette::ToolTipBase, brush7); palette5.setBrush(QPalette::Disabled, QPalette::ToolTipText, brush6); - head->setPalette(palette5); - head->setAutoFillBackground(true); - iconsLayout = new QHBoxLayout(head); + foot->setPalette(palette5); + foot->setAutoFillBackground(true); + + iconsLayout = new QHBoxLayout(foot); iconsLayout->setSpacing(0); iconsLayout->setObjectName(QStringLiteral("iconsLayout")); iconsLayout->setContentsMargins(0, 0, 0, 0); - generalButton = new QPushButton(head); + generalButton = new QPushButton(foot); generalButton->setObjectName(QStringLiteral("generalButton")); generalButton->setMinimumSize(QSize(55, 35)); generalButton->setMaximumSize(QSize(55, 35)); @@ -114,7 +139,7 @@ SettingsWidget::SettingsWidget() generalButton->setFlat(true); iconsLayout->addWidget(generalButton); - identityButton = new QPushButton(head); + identityButton = new QPushButton(foot); identityButton->setObjectName(QStringLiteral("identityButton")); identityButton->setMinimumSize(QSize(55, 35)); identityButton->setMaximumSize(QSize(55, 35)); @@ -125,7 +150,7 @@ SettingsWidget::SettingsWidget() identityButton->setFlat(true); iconsLayout->addWidget(identityButton); - privacyButton = new QPushButton(head); + privacyButton = new QPushButton(foot); privacyButton->setObjectName(QStringLiteral("privacyButton")); privacyButton->setMinimumSize(QSize(55, 35)); privacyButton->setMaximumSize(QSize(55, 35)); @@ -136,7 +161,7 @@ SettingsWidget::SettingsWidget() privacyButton->setFlat(true); iconsLayout->addWidget(privacyButton); - avButton = new QPushButton(head); + avButton = new QPushButton(foot); avButton->setObjectName(QStringLiteral("avButton")); avButton->setMinimumSize(QSize(55, 35)); avButton->setMaximumSize(QSize(55, 35)); @@ -146,19 +171,4 @@ SettingsWidget::SettingsWidget() avButton->setIcon(icon4); avButton->setFlat(true); iconsLayout->addWidget(avButton); - - head->setLayout(iconsLayout); - -} - -SettingsWidget::~SettingsWidget() -{ -} - -void SettingsWidget::show(Ui::MainWindow& ui) -{ - ui.mainContent->layout()->addWidget(main); - ui.mainHead->layout()->addWidget(head); - main->show(); - head->show(); } diff --git a/widget/form/settingswidget.h b/widget/form/settingswidget.h index a1cee909f..c901ce906 100644 --- a/widget/form/settingswidget.h +++ b/widget/form/settingswidget.h @@ -17,21 +17,15 @@ #ifndef SETTINGSWIDGET_H #define SETTINGSWIDGET_H -#include -#include -#include -#include -#include +#include #include -#include -#include - +#include #include "widget/croppinglabel.h" namespace Ui {class MainWindow;} class QString; -class SettingsWidget : public QObject +class SettingsWidget : public QWidget { Q_OBJECT public: @@ -46,7 +40,9 @@ public slots: private slots: private: - QWidget *main, *head; + QWidget *_main, *main, *head, *foot; + // _main consists of main+foot + QVBoxLayout *_mainLayout; // the code pertaining to the icons is mostly copied from ui_mainwindow.h QHBoxLayout *iconsLayout; QPushButton *generalButton; @@ -56,6 +52,10 @@ private: // now the actual pages and stuff // ... + + + + void prepButtons(); // just so I can move the crap to the bottom of the file public: }; From aa801f9615ecb052129c512861c42c69de4f6a86 Mon Sep 17 00:00:00 2001 From: bill Date: Mon, 15 Sep 2014 05:45:59 -0500 Subject: [PATCH 029/205] new settings infrastructure done, though there's a double free or something in ~Widget() --- qtox.pro | 9 ++++ widget/form/settings/avform.cpp | 26 ++++++++++ widget/form/settings/avform.h | 33 ++++++++++++ widget/form/settings/generalform.cpp | 46 ++++++++++++++++ widget/form/settings/generalform.h | 41 +++++++++++++++ widget/form/settings/genericsettings.h | 46 ++++++++++++++++ widget/form/settings/identityform.cpp | 38 ++++++++++++++ widget/form/settings/identityform.h | 34 ++++++++++++ widget/form/settings/privacyform.cpp | 27 ++++++++++ widget/form/settings/privacyform.h | 33 ++++++++++++ widget/form/settingswidget.cpp | 72 +++++++++++++++++++++++--- widget/form/settingswidget.h | 41 +++++++++------ 12 files changed, 423 insertions(+), 23 deletions(-) create mode 100644 widget/form/settings/avform.cpp create mode 100644 widget/form/settings/avform.h create mode 100644 widget/form/settings/generalform.cpp create mode 100644 widget/form/settings/generalform.h create mode 100644 widget/form/settings/genericsettings.h create mode 100644 widget/form/settings/identityform.cpp create mode 100644 widget/form/settings/identityform.h create mode 100644 widget/form/settings/privacyform.cpp create mode 100644 widget/form/settings/privacyform.h diff --git a/qtox.pro b/qtox.pro index ce7762e79..7399e260f 100644 --- a/qtox.pro +++ b/qtox.pro @@ -80,6 +80,11 @@ HEADERS += widget/form/addfriendform.h \ widget/form/chatform.h \ widget/form/groupchatform.h \ widget/form/settingswidget.h \ + widget/form/settings/genericsettings.h \ + widget/form/settings/generalform.h \ + widget/form/settings/identityform.h \ + widget/form/settings/privacyform.h \ + widget/form/settings/avform.h \ widget/form/filesform.h \ widget/tool/chattextedit.h \ widget/tool/friendrequestdialog.h \ @@ -117,6 +122,10 @@ SOURCES += \ widget/form/chatform.cpp \ widget/form/groupchatform.cpp \ widget/form/settingswidget.cpp \ + widget/form/settings/generalform.cpp \ + widget/form/settings/identityform.cpp \ + widget/form/settings/privacyform.cpp \ + widget/form/settings/avform.cpp \ widget/form/filesform.cpp \ widget/tool/chattextedit.cpp \ widget/tool/friendrequestdialog.cpp \ diff --git a/widget/form/settings/avform.cpp b/widget/form/settings/avform.cpp new file mode 100644 index 000000000..347a1cfbb --- /dev/null +++ b/widget/form/settings/avform.cpp @@ -0,0 +1,26 @@ +/* + Copyright (C) 2014 by Project Tox + + This file is part of qTox, a Qt-based graphical interface for Tox. + + This program 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. + 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 COPYING file for more details. +*/ + +#include "avform.h" + +AVForm::AVForm() +{ + prep(); +} + +AVForm::~AVForm() +{ +} diff --git a/widget/form/settings/avform.h b/widget/form/settings/avform.h new file mode 100644 index 000000000..e214e133e --- /dev/null +++ b/widget/form/settings/avform.h @@ -0,0 +1,33 @@ +/* + Copyright (C) 2014 by Project Tox + + This file is part of qTox, a Qt-based graphical interface for Tox. + + This program 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. + 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 COPYING file for more details. +*/ + +#ifndef AVFORM_H +#define AVFORM_H + +#include "genericsettings.h" + +class AVForm : public GenericForm +{ + Q_OBJECT +public: + AVForm(); + ~AVForm(); + +private: + +}; + +#endif diff --git a/widget/form/settings/generalform.cpp b/widget/form/settings/generalform.cpp new file mode 100644 index 000000000..050d4f7eb --- /dev/null +++ b/widget/form/settings/generalform.cpp @@ -0,0 +1,46 @@ +/* + Copyright (C) 2014 by Project Tox + + This file is part of qTox, a Qt-based graphical interface for Tox. + + This program 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. + 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 COPYING file for more details. +*/ + +#include "generalform.h" +#include "widget/form/settingswidget.h" + +GeneralForm::GeneralForm() +{ + prep(); + group = new QGroupBox(tr("General Settings")); + enableIPv6 = new QCheckBox(); + enableIPv6->setText(tr("Enable IPv6 (recommended)","Text on a checkbox to enable IPv6")); + useTranslations = new QCheckBox(); + useTranslations->setText(tr("Use translations","Text on a checkbox to enable translations")); + makeToxPortable = new QCheckBox(); + makeToxPortable->setText(tr("Make Tox portable","Text on a checkbox to make qTox a portable application")); + makeToxPortable->setToolTip(tr("Save settings to the working directory instead of the usual conf dir","describes makeToxPortable checkbox")); + + QVBoxLayout *vLayout = new QVBoxLayout(); + vLayout->addWidget(enableIPv6); + vLayout->addWidget(useTranslations); + vLayout->addWidget(makeToxPortable); + group->setLayout(vLayout); + + label.setText(tr("General Settings")); + + headLayout.addWidget(&label); + layout.addWidget(group); +} + +GeneralForm::~GeneralForm() +{ +} diff --git a/widget/form/settings/generalform.h b/widget/form/settings/generalform.h new file mode 100644 index 000000000..c484a436d --- /dev/null +++ b/widget/form/settings/generalform.h @@ -0,0 +1,41 @@ +/* + Copyright (C) 2014 by Project Tox + + This file is part of qTox, a Qt-based graphical interface for Tox. + + This program 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. + 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 COPYING file for more details. +*/ + +#ifndef GENERALFORM_H +#define GENERALFORM_H + +#include "genericsettings.h" +#include +#include +#include + + +class GeneralForm : public GenericForm +{ + Q_OBJECT +public: + GeneralForm(); + ~GeneralForm(); + +private: + QGroupBox *group; + QCheckBox* enableIPv6; + QCheckBox* useTranslations; + QCheckBox* makeToxPortable; + QLabel label; +}; + +#endif diff --git a/widget/form/settings/genericsettings.h b/widget/form/settings/genericsettings.h new file mode 100644 index 000000000..9353d21df --- /dev/null +++ b/widget/form/settings/genericsettings.h @@ -0,0 +1,46 @@ +/* + Copyright (C) 2014 by Project Tox + + This file is part of qTox, a Qt-based graphical interface for Tox. + + This program 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. + 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 COPYING file for more details. +*/ + +#ifndef GENERICFORM_H +#define GENERICFORM_H + +#include +#include +#include "widget/form/settingswidget.h" + +class GenericForm : public QObject +{ + Q_OBJECT +public: + virtual void show(SettingsWidget& sw) + { + sw.body->layout()->addWidget(&body); + body.show(); + sw.head->layout()->addWidget(&head); + head.show(); + } + +protected: + QVBoxLayout layout, headLayout; + QWidget head, body; + void prep() // call in subclass constructor + { + head.setLayout(&headLayout); + body.setLayout(&layout); + } +}; + +#endif diff --git a/widget/form/settings/identityform.cpp b/widget/form/settings/identityform.cpp new file mode 100644 index 000000000..dbd5574c5 --- /dev/null +++ b/widget/form/settings/identityform.cpp @@ -0,0 +1,38 @@ +/* + Copyright (C) 2014 by Project Tox + + This file is part of qTox, a Qt-based graphical interface for Tox. + + This program 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. + 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 COPYING file for more details. +*/ + +#include "identityform.h" +#include "widget/form/settingswidget.h" +#include +#include + +IdentityForm::IdentityForm() +{ + prep(); + toxGroup = new QGroupBox(tr("Tox ID")); + QLabel* toxIdLabel = new QLabel(tr("Your Tox ID")); + QLineEdit* toxID = new QLineEdit(); + toxID->setReadOnly(true); + QVBoxLayout* toxLayout = new QVBoxLayout(); + toxLayout->addWidget(toxIdLabel); + toxLayout->addWidget(toxID); + toxGroup->setLayout(toxLayout); + layout.addWidget(toxGroup); +} + +IdentityForm::~IdentityForm() +{ +} diff --git a/widget/form/settings/identityform.h b/widget/form/settings/identityform.h new file mode 100644 index 000000000..dc616d75e --- /dev/null +++ b/widget/form/settings/identityform.h @@ -0,0 +1,34 @@ +/* + Copyright (C) 2014 by Project Tox + + This file is part of qTox, a Qt-based graphical interface for Tox. + + This program 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. + 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 COPYING file for more details. +*/ + +#ifndef IDENTITYFORM_H +#define IDENTITYFORM_H + +#include "genericsettings.h" +#include + +class IdentityForm : public GenericForm +{ + Q_OBJECT +public: + IdentityForm(); + ~IdentityForm(); + +private: + QGroupBox* toxGroup; +}; + +#endif diff --git a/widget/form/settings/privacyform.cpp b/widget/form/settings/privacyform.cpp new file mode 100644 index 000000000..856f64954 --- /dev/null +++ b/widget/form/settings/privacyform.cpp @@ -0,0 +1,27 @@ +/* + Copyright (C) 2014 by Project Tox + + This file is part of qTox, a Qt-based graphical interface for Tox. + + This program 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. + 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 COPYING file for more details. +*/ + +#include "privacyform.h" +#include "widget/form/settingswidget.h" + +PrivacyForm::PrivacyForm() +{ + prep(); +} + +PrivacyForm::~PrivacyForm() +{ +} diff --git a/widget/form/settings/privacyform.h b/widget/form/settings/privacyform.h new file mode 100644 index 000000000..ae1e61956 --- /dev/null +++ b/widget/form/settings/privacyform.h @@ -0,0 +1,33 @@ +/* + Copyright (C) 2014 by Project Tox + + This file is part of qTox, a Qt-based graphical interface for Tox. + + This program 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. + 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 COPYING file for more details. +*/ + +#ifndef PRIVACYFORM_H +#define PRIVACYFORM_H + +#include "genericsettings.h" + +class PrivacyForm : public GenericForm +{ + Q_OBJECT +public: + PrivacyForm(); + ~PrivacyForm(); + +private: + +}; + +#endif diff --git a/widget/form/settingswidget.cpp b/widget/form/settingswidget.cpp index fcbd2a981..3a13c1cdb 100644 --- a/widget/form/settingswidget.cpp +++ b/widget/form/settingswidget.cpp @@ -17,21 +17,41 @@ #include "settingswidget.h" #include "widget/widget.h" #include "ui_mainwindow.h" +#include "widget/form/settings/generalform.h" +#include "widget/form/settings/identityform.h" +#include "widget/form/settings/privacyform.h" +#include "widget/form/settings/avform.h" SettingsWidget::SettingsWidget() : QWidget() { - _main = new QWidget(); + generalForm = new GeneralForm(); + identityForm = new IdentityForm(); + privacyForm = new PrivacyForm(); + avForm = new AVForm(); + main = new QWidget(); + body = new QWidget(); head = new QWidget(); foot = new QWidget(); + + head->setLayout(new QVBoxLayout()); + body->setLayout(new QVBoxLayout()); + prepButtons(); foot->setLayout(iconsLayout); - _mainLayout = new QVBoxLayout(_main); - _mainLayout->addWidget(main); - _mainLayout->addWidget(foot); + mainLayout = new QVBoxLayout(main); + mainLayout->addWidget(body); + mainLayout->addWidget(foot); // something something foot size - _main->setLayout(_mainLayout); + main->setLayout(mainLayout); + + connect(generalButton, &QPushButton::clicked, this, &SettingsWidget::onGeneralClicked); + connect(identityButton, &QPushButton::clicked, this, &SettingsWidget::onIdentityClicked); + connect(privacyButton, &QPushButton::clicked, this, &SettingsWidget::onPrivacyClicked); + connect(avButton, &QPushButton::clicked, this, &SettingsWidget::onAVClicked); + + active = generalForm; } SettingsWidget::~SettingsWidget() @@ -40,12 +60,50 @@ SettingsWidget::~SettingsWidget() void SettingsWidget::show(Ui::MainWindow& ui) { - ui.mainContent->layout()->addWidget(_main); + active->show(*this); + ui.mainContent->layout()->addWidget(main); ui.mainHead->layout()->addWidget(head); - _main->show(); + main->show(); head->show(); } +void SettingsWidget::onGeneralClicked() +{ + hideSettingsForms(); + active = generalForm; + generalForm->show(*this); +} + +void SettingsWidget::onIdentityClicked() +{ + hideSettingsForms(); + active = identityForm; + identityForm->show(*this); +} + +void SettingsWidget::onPrivacyClicked() +{ + hideSettingsForms(); + active = privacyForm; + privacyForm->show(*this); +} + +void SettingsWidget::onAVClicked() +{ + hideSettingsForms(); + active = avForm; + avForm->show(*this); +} + +void SettingsWidget::hideSettingsForms() +{ + QLayoutItem *item; + while ((item = head->layout()->takeAt(0)) != 0) + item->widget()->hide(); + while ((item = body->layout()->takeAt(0)) != 0) + item->widget()->hide(); +} + void SettingsWidget::prepButtons() { // this crap is copied from ui_mainwindow.h... there's no easy way around diff --git a/widget/form/settingswidget.h b/widget/form/settingswidget.h index c901ce906..6ee45f90d 100644 --- a/widget/form/settingswidget.h +++ b/widget/form/settingswidget.h @@ -19,11 +19,12 @@ #include #include -#include -#include "widget/croppinglabel.h" - -namespace Ui {class MainWindow;} -class QString; +class GenericForm; +class GeneralForm; +class IdentityForm; +class PrivacyForm; +class AVForm; +namespace Ui {class MainWindow;}; class SettingsWidget : public QWidget { @@ -33,30 +34,38 @@ public: ~SettingsWidget(); void show(Ui::MainWindow &ui); + + QWidget *head, *body; // keep the others private public slots: //void setFriendAddress(const QString& friendAddress); private slots: + void onGeneralClicked(); + void onIdentityClicked(); + void onPrivacyClicked(); + void onAVClicked(); private: - QWidget *_main, *main, *head, *foot; - // _main consists of main+foot - QVBoxLayout *_mainLayout; + QWidget *main, *foot; + // main consists of body+foot for Ui::MainWindow + QVBoxLayout *mainLayout; + + GenericForm* active; + GeneralForm* generalForm; + IdentityForm* identityForm; + PrivacyForm* privacyForm; + AVForm* avForm; + void hideSettingsForms(); + + // the code pertaining to the icons is mostly copied from ui_mainwindow.h QHBoxLayout *iconsLayout; QPushButton *generalButton; QPushButton *identityButton; QPushButton *privacyButton; QPushButton *avButton; - - // now the actual pages and stuff - // ... - - - void prepButtons(); // just so I can move the crap to the bottom of the file -public: }; -#endif // SETTINGSFORM_H +#endif // SETTINGSWIDGET_H From d7df703b87dd8547f96e951cdb230d8b2992dec6 Mon Sep 17 00:00:00 2001 From: Ansa89 Date: Mon, 15 Sep 2014 15:17:20 +0200 Subject: [PATCH 030/205] Italian translation: update --- translations/it.qm | Bin 5820 -> 7125 bytes translations/it.ts | 103 +++++++++++---------------------------------- 2 files changed, 25 insertions(+), 78 deletions(-) diff --git a/translations/it.qm b/translations/it.qm index 2523c49cbbb5ce0bc93e6891af285cbe0d984d2e..b61df4ac4e148c46c9e020b5a5d38bbd1a45673e 100644 GIT binary patch delta 1661 zcmaJ=eM}p57=GK{^(fE-+JR*w@nA5_GQ#3E7b3}4WkR<^a3FJXh#B!KPJQk=I-J8??%vBFB~dVt8@M8rNpbk~o>yz&x}?+P)aV??Ee z#5Qdp@_a~KcNbAfGp+xNAFdCth{y$ly72R&O1Vsw~IYC z@EMVJ3;X_&3q;JRO!Ow$i&G%mc$@7(j48@ZDw0&w8n+~3|E+Xm+W;hNtCma-yTV! zhxhZ_2gX743*TCXeAhnyc<2O#^z&D%&jRO>f`eDhNDAyz9T-&7LnKp_!X%PF5sY+7 zB&|s=HaaMXaX81!apLtfDUvKC@X>`xR8A;zFK2G~+grp=*_J`{Qv#2&7;$O9)-JvG zcEF;4Bd(%A>KSjzy(n6wCAdteO(02V@7nP&DwoLR0Zwgoaf@PGtzx=79g7OFk!c{)G@%XO-G~8d$mZrjbW}+H?YVAG^5nK-s6u}vqV}0B z;TOa-D59!&TE9vOvf?CJmDW-_q6CHdEe3yFQuJD@ze{15%vusc;~-ZTnd5v=)Pl0Q zR9@k2_TTb^yJ`PYnLPY7uSp2?s+nq&*5$|vNU~-q#*%s&YNl;jb@t}&|EExJi$pZ6 xFPp-(M3saX{0~9tf}^XbC)=wUvtPJ4cUKklwCTHr*=JMPKk5#|sh^6^{R6Z0gVz86 delta 535 zcmX9*T}YE*7(L&<_uckw-@a{b%4q8%QS3&Fa#>JBQD}pZ)UZHS&T=SJ;mawNDo{GjK{0! zofbE@@$K`7i6MmoaWNG>47iuYOwD(|c2E4we42Yk^6vh74ud)535aE)ni#_y1)Y9BmY)b-i*Yq)`W zYu(W@QH|?O>!};4)K7NMfb&w9zEU?0cwT!F`93;q^2}G48D*5nh}bD+NN|OW$cAc0 zI%!1G3I4lbY#xnsP|9fS;|cuzM(f}dPa%!A2>DLM$RB^eL9;!yU$zcZg$hY^QWhR+ imc20M%PR%5V!>ujR3@wrHCX7WnzLD71DmWJ;q*TOIgTO# diff --git a/translations/it.ts b/translations/it.ts index 35b4c928d..c7abbc341 100644 --- a/translations/it.ts +++ b/translations/it.ts @@ -6,20 +6,20 @@ Video Settings - + Impostazioni Webcam Show video preview On a button - + Avvia prova webcam Hide video preview On a button - + Ferma prova webcam @@ -62,7 +62,7 @@ You can't add yourself as a friend! When trying to add your own Tox ID as friend - + Non puoi aggiungere te stesso come contatto! @@ -212,41 +212,41 @@ General Settings - + Impostazioni Generali Enable IPv6 (recommended) Text on a checkbox to enable IPv6 - Abilita IPv6 (consigliato) + Abilita IPv6 (consigliato) Use translations Text on a checkbox to enable translations - Abilita traduzioni + Abilita traduzioni Make Tox portable Text on a checkbox to make qTox a portable application - Rendi qTox portabile + Rendi qTox portabile Save settings to the working directory instead of the usual conf dir describes makeToxPortable checkbox - Slava le impostazioni nella directory di lavoro corrente, invece della directory di default + Slava le impostazioni nella directory di lavoro corrente, invece della directory di default Theme - + Tema Smiley Pack - Emoticons + Emoticons @@ -303,29 +303,29 @@ Public Information - + Informazioni Pubbliche Name Username/nick - Nome + Nome Status Status message - Stato + Stato Tox ID - Tox ID + Tox ID Your Tox ID - + Il tuo Tox ID @@ -390,95 +390,42 @@ qTox – Settings - + qTox - Impostazioni General - + Generale Identity - + Profilo Privacy - + Privacy Audio/Video - + Audio/Video Ok - + OK Cancel - + Annulla Apply - - - - - SettingsForm - - User Settings - "Headline" of the window - Impostazioni - - - Name - Username/nick - Nome - - - Status - Status message - Stato - - - (click here to copy) - Click on this text to copy TID to clipboard - (clicca qui per copiare) - - - Test video - Text on a button to test the video/webcam - Prova la webcam - - - Enable IPv6 (recommended) - Text on a checkbox to enable IPv6 - Abilita IPv6 (consigliato) - - - Use translations - Text on a checkbox to enable translations - Abilita traduzioni - - - Make Tox portable - Text on a checkbox to make qTox a portable application - Rendi qTox portabile - - - Save settings to the working directory instead of the usual conf dir - describes makeToxPortable checkbox - Slava le impostazioni nella directory di lavoro corrente, invece della directory di default - - - Smiley Pack - Text on smiley pack label - Emoticons + Applica @@ -505,7 +452,7 @@ <Unknown> Placeholder when we don't know someone's name in a group chat - <Sconosciuto> + <Sconosciuto> From 5dc41282156f0d83c03f314c937d7688aeb1ca53 Mon Sep 17 00:00:00 2001 From: dubslow Date: Mon, 15 Sep 2014 08:31:42 -0500 Subject: [PATCH 031/205] cosmetics --- widget/form/settings/avform.cpp | 2 ++ widget/form/settings/generalform.cpp | 2 ++ widget/form/settings/genericsettings.h | 8 +++++++- widget/form/settings/identityform.cpp | 2 ++ widget/form/settings/privacyform.cpp | 2 ++ widget/form/settingswidget.cpp | 2 +- 6 files changed, 16 insertions(+), 2 deletions(-) diff --git a/widget/form/settings/avform.cpp b/widget/form/settings/avform.cpp index 347a1cfbb..5c0b38da3 100644 --- a/widget/form/settings/avform.cpp +++ b/widget/form/settings/avform.cpp @@ -19,6 +19,8 @@ AVForm::AVForm() { prep(); + icon.addFile(":/img/settings/av.png"); + label.setText(tr("Audio/Video settings")); } AVForm::~AVForm() diff --git a/widget/form/settings/generalform.cpp b/widget/form/settings/generalform.cpp index 050d4f7eb..a9810c1ae 100644 --- a/widget/form/settings/generalform.cpp +++ b/widget/form/settings/generalform.cpp @@ -20,6 +20,8 @@ GeneralForm::GeneralForm() { prep(); + icon.addFile(":/img/settings/general.png"); + label.setText(tr("General settings")); group = new QGroupBox(tr("General Settings")); enableIPv6 = new QCheckBox(); enableIPv6->setText(tr("Enable IPv6 (recommended)","Text on a checkbox to enable IPv6")); diff --git a/widget/form/settings/genericsettings.h b/widget/form/settings/genericsettings.h index 9353d21df..94f8fe90f 100644 --- a/widget/form/settings/genericsettings.h +++ b/widget/form/settings/genericsettings.h @@ -34,13 +34,19 @@ public: } protected: - QVBoxLayout layout, headLayout; + QVBoxLayout layout; + QHBoxLayout headLayout; + QIcon icon; + QLabel label; QWidget head, body; void prep() // call in subclass constructor { head.setLayout(&headLayout); + headLayout.addWidget(&icon); + headLayout.addWidget(&label); body.setLayout(&layout); } + }; #endif diff --git a/widget/form/settings/identityform.cpp b/widget/form/settings/identityform.cpp index dbd5574c5..ac89257a9 100644 --- a/widget/form/settings/identityform.cpp +++ b/widget/form/settings/identityform.cpp @@ -22,6 +22,8 @@ IdentityForm::IdentityForm() { prep(); + icon.addFile(":/img/settings/identity.png"); + label.setText(tr("Your identity")); toxGroup = new QGroupBox(tr("Tox ID")); QLabel* toxIdLabel = new QLabel(tr("Your Tox ID")); QLineEdit* toxID = new QLineEdit(); diff --git a/widget/form/settings/privacyform.cpp b/widget/form/settings/privacyform.cpp index 856f64954..ef7c54c4b 100644 --- a/widget/form/settings/privacyform.cpp +++ b/widget/form/settings/privacyform.cpp @@ -20,6 +20,8 @@ PrivacyForm::PrivacyForm() { prep(); + icon.addFile(":/img/settings/privacy.png"); + label.setText(tr("Privacy settings")); } PrivacyForm::~PrivacyForm() diff --git a/widget/form/settingswidget.cpp b/widget/form/settingswidget.cpp index 3a13c1cdb..9b5dc7856 100644 --- a/widget/form/settingswidget.cpp +++ b/widget/form/settingswidget.cpp @@ -110,7 +110,7 @@ void SettingsWidget::prepButtons() // just straight up copying it like this... oh well // the layout/icons obviously need to be improved, but it's a working model, // not a pretty one - QSizePolicy sizePolicy3(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); + QSizePolicy sizePolicy3(QSizePolicy::Fixed, QSizePolicy::Fixed); sizePolicy3.setHorizontalStretch(0); sizePolicy3.setVerticalStretch(0); foot->setObjectName(QStringLiteral("foot")); From b56739264985d35b0fbb1201e67cf954a5ccf638 Mon Sep 17 00:00:00 2001 From: Marcel Date: Fri, 12 Sep 2014 15:50:39 +0200 Subject: [PATCH 032/205] added images --- img/settings/av.png | Bin 0 -> 6360 bytes img/settings/general.png | Bin 0 -> 2902 bytes img/settings/identity.png | Bin 0 -> 4771 bytes img/settings/privacy.png | Bin 0 -> 1883 bytes res.qrc | 4 ++++ 5 files changed, 4 insertions(+) create mode 100644 img/settings/av.png create mode 100644 img/settings/general.png create mode 100644 img/settings/identity.png create mode 100644 img/settings/privacy.png diff --git a/img/settings/av.png b/img/settings/av.png new file mode 100644 index 0000000000000000000000000000000000000000..f96f88ea84299b2428780a15d29ae37db6601c90 GIT binary patch literal 6360 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 A^8f$< literal 0 HcmV?d00001 diff --git a/img/settings/identity.png b/img/settings/identity.png new file mode 100644 index 0000000000000000000000000000000000000000..806bb525efc2ea73d087891152331199cf543f99 GIT binary patch literal 4771 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 literal 0 HcmV?d00001 diff --git a/img/settings/privacy.png b/img/settings/privacy.png new file mode 100644 index 0000000000000000000000000000000000000000..763478290b8b0592c3f155013ad7d4f4637608d1 GIT binary patch literal 1883 zcmV-h2c-CkP)gtR(J>n?~InQFIz8Zp$*KF3uN*QzsEcO+*L2 zVsvxPDEeXVbMj$R=K|s@i$dni#++G1%<$~a5JaK4vQi3dub1wFHSvXNOYd!Z;rzd~ z_c_mVpZ@N1&ON8+UVw^xFDhcjDpmk^#SmvO+S+WVD3HKm zYy_}Q!Vu#PaR#rg%~nmvkf+0#0pRr0&Mhh`sv|Km@lVrWQGR+?hrBca%_03oNgM|SAEX#HuJalk>baeC`KPCyj*q}fjR))U=>FMdE zNl8gvy>*3}54JLMf2cq_OCnyMlD0hP@mC6-l?0yZT zM>!mhp=VB?87zjc&aTdZk)ChF1L1jIyX&J}3wfRoxk@@59R>;{M0vel#jRVnUf5W) zaZ)ILTrQW=X0s(zARn((jj^>8+2_L!~1HL5QY6M3UR>)-PMStf;1@Cbl>2 zD~?yB$steK00DsZ_V(fLE_(Ol{8jl=?RNWsK-<;S)Wp`;*Qd)N$4FXS3~FbHN~N+7 z89L-z{Gj+I(_oWz?6|QvoE=V;Uaxo0nLDT9LED*GGvB{ne|_qc{1J{Q`V|m!irD~Q z1%TH8j0B*QB2Gp|#;5!C@B8Wg=MC#OOgehx=&Ih_aRc}pKskUC!jXUbOqXR&F~1Ig z1F#9e^HRZ3C=}gu-=2H<{^!k`Hjh8{!?6{;bf@#3>m~r4F9-Qoh%b>J!x1a_+2jjn z&Ys!pa5$KyOP0?1F;c@|7{;^vlih2ps;bPD zXDeqpoz5Xr+*bfdAso3QS0LK}6o#YJS(g1z5QHe6=d}`tDkdB$lIs`}mVVba6MrTQ zFeJ}OY9OP~_atdf10+6qNtd;wqN1Gf@$vQAf!a2uQYmyeI$~Q|T1HD;DQYC;QMZQpiYr_(*OTg2gTFhw5}rB_x~z7wV{Ojd)s=+9+DM@P5q*tuhqCChUANp>es zoE);gVEvY^uC7?I&q2yry;5cukT-8--ma&?002vt<#yi6yj{NegKQ)#AS04TT+CUV zLjtwWS)4;gB#*dAfk>pZw6qK1XhVSnsEHFNHin}O1rnfQV`JUnXhVSnsLPix$A_a0 z1rngnojW%!9Bn9&09AXXc1G=$T3rzKy4owXGbj*=#Phs1cX@7JApfV^?e+n=%X9PO zHd~k5#1PHR&0{Q?mcr_)YNJ1!>Z)p^CDT&a+}u1yZu!X$2mrKNTSsr*vNgM|uI{n! ztFEq2w{^?b>{e^*XgTI4yS1#ixVY>2tMfm5bZ5z<`u@A`llFYFXNk>b6MeZ{%C#(6 z0ZD!~`NH8NhY#rW`n!SH+wJxNv)`JXd*h!QFUtjpY`QFy$#k`>ysRWp7yzKx>+hD8 zmz9`IrmJ)e5m5}oxQn+JAL#8vpT*mY4=@blra(keYHI5F$x|lxdZ)+aDU4WWrS7uI`{1}+E@vQn0d({s7#+Tx literal 0 HcmV?d00001 diff --git a/res.qrc b/res.qrc index cbf038a58..6a121b0ad 100644 --- a/res.qrc +++ b/res.qrc @@ -135,5 +135,9 @@ ui/fileTransferInstance/emptyRGreenFileButton.png ui/fileTransferInstance/emptyRRedFileButton.png audio/notification.pcm + img/settings/general.png + img/settings/identity.png + img/settings/privacy.png + img/settings/av.png From d971d7e6477741b9a7859f793a49c317cf5ec545 Mon Sep 17 00:00:00 2001 From: dubslow Date: Mon, 15 Sep 2014 08:48:17 -0500 Subject: [PATCH 033/205] scaling still isn't quite right... --- widget/form/settings/avform.cpp | 2 +- widget/form/settings/generalform.cpp | 2 +- widget/form/settings/genericsettings.h | 4 ++-- widget/form/settings/identityform.cpp | 2 +- widget/form/settings/privacyform.cpp | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/widget/form/settings/avform.cpp b/widget/form/settings/avform.cpp index 5c0b38da3..e0b0773f9 100644 --- a/widget/form/settings/avform.cpp +++ b/widget/form/settings/avform.cpp @@ -19,7 +19,7 @@ AVForm::AVForm() { prep(); - icon.addFile(":/img/settings/av.png"); + icon.setPixmap(QPixmap(":/img/settings/av.png").scaledToHeight(headLayout.sizeHint().height(), Qt::SmoothTransformation)); label.setText(tr("Audio/Video settings")); } diff --git a/widget/form/settings/generalform.cpp b/widget/form/settings/generalform.cpp index a9810c1ae..7a6734383 100644 --- a/widget/form/settings/generalform.cpp +++ b/widget/form/settings/generalform.cpp @@ -20,7 +20,7 @@ GeneralForm::GeneralForm() { prep(); - icon.addFile(":/img/settings/general.png"); + icon.setPixmap(QPixmap(":/img/settings/general.png").scaledToHeight(headLayout.sizeHint().height(), Qt::SmoothTransformation)); label.setText(tr("General settings")); group = new QGroupBox(tr("General Settings")); enableIPv6 = new QCheckBox(); diff --git a/widget/form/settings/genericsettings.h b/widget/form/settings/genericsettings.h index 94f8fe90f..760d39cb0 100644 --- a/widget/form/settings/genericsettings.h +++ b/widget/form/settings/genericsettings.h @@ -19,6 +19,7 @@ #include #include +#include #include "widget/form/settingswidget.h" class GenericForm : public QObject @@ -36,8 +37,7 @@ public: protected: QVBoxLayout layout; QHBoxLayout headLayout; - QIcon icon; - QLabel label; + QLabel label, icon; QWidget head, body; void prep() // call in subclass constructor { diff --git a/widget/form/settings/identityform.cpp b/widget/form/settings/identityform.cpp index ac89257a9..696b2141a 100644 --- a/widget/form/settings/identityform.cpp +++ b/widget/form/settings/identityform.cpp @@ -22,7 +22,7 @@ IdentityForm::IdentityForm() { prep(); - icon.addFile(":/img/settings/identity.png"); + icon.setPixmap(QPixmap(":/img/settings/identity.png").scaledToHeight(headLayout.sizeHint().height(), Qt::SmoothTransformation)); label.setText(tr("Your identity")); toxGroup = new QGroupBox(tr("Tox ID")); QLabel* toxIdLabel = new QLabel(tr("Your Tox ID")); diff --git a/widget/form/settings/privacyform.cpp b/widget/form/settings/privacyform.cpp index ef7c54c4b..e1f737975 100644 --- a/widget/form/settings/privacyform.cpp +++ b/widget/form/settings/privacyform.cpp @@ -20,7 +20,7 @@ PrivacyForm::PrivacyForm() { prep(); - icon.addFile(":/img/settings/privacy.png"); + icon.setPixmap(QPixmap(":/img/settings/privacy.png").scaledToHeight(headLayout.sizeHint().height(), Qt::SmoothTransformation)); label.setText(tr("Privacy settings")); } From ecd922c72dec2c1b1ed63028644f9f4cf004d639 Mon Sep 17 00:00:00 2001 From: apprb Date: Tue, 16 Sep 2014 00:51:25 +0700 Subject: [PATCH 034/205] fix: Force video output to follow aspect ratio #130 --- widget/netcamview.cpp | 12 +++++++++--- widget/netcamview.h | 5 +++++ widget/selfcamview.cpp | 9 +++++++-- widget/selfcamview.h | 3 +++ 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/widget/netcamview.cpp b/widget/netcamview.cpp index 4268ea8dd..fc94393d5 100644 --- a/widget/netcamview.cpp +++ b/widget/netcamview.cpp @@ -59,7 +59,7 @@ NetCamView::NetCamView(QWidget* parent) setWindowTitle("Tox video"); setMinimumSize(320,240); - displayLabel->setScaledContents(true); + displayLabel->setAlignment(Qt::AlignCenter); mainLayout->addWidget(displayLabel); } @@ -73,10 +73,10 @@ void NetCamView::updateDisplay(vpx_image* frame) core->increaseVideoBusyness(); - QImage img = convert(*frame); + img = convert(*frame); vpx_img_free(frame); - displayLabel->setPixmap(QPixmap::fromImage(img)); + displayLabel->setPixmap(QPixmap::fromImage(img).scaled(displayLabel->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation)); core->decreaseVideoBusyness(); } @@ -108,3 +108,9 @@ QImage NetCamView::convert(vpx_image& frame) return img; } + +void NetCamView::resizeEvent(QResizeEvent *e) +{ + Q_UNUSED(e) + displayLabel->setPixmap(QPixmap::fromImage(img).scaled(displayLabel->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation)); +} diff --git a/widget/netcamview.h b/widget/netcamview.h index 0aba0edd9..a8698eaa3 100644 --- a/widget/netcamview.h +++ b/widget/netcamview.h @@ -24,6 +24,7 @@ class QShowEvent; class QPainter; class QLabel; class QHBoxLayout; +class QImage; class vpx_image; class NetCamView : public QWidget @@ -39,10 +40,14 @@ public slots: private: static QImage convert(vpx_image& frame); +protected: + void resizeEvent(QResizeEvent *e); + private: QLabel *displayLabel; QImage lastFrame; QHBoxLayout* mainLayout; + QImage img; }; #endif // NETCAMVIEW_H diff --git a/widget/selfcamview.cpp b/widget/selfcamview.cpp index 6436e24d9..7e9c3d252 100644 --- a/widget/selfcamview.cpp +++ b/widget/selfcamview.cpp @@ -36,7 +36,7 @@ SelfCamView::SelfCamView(Camera* Cam, QWidget* parent) updateDisplayTimer->setInterval(5); updateDisplayTimer->setSingleShot(false); - displayLabel->setScaledContents(true); + displayLabel->setAlignment(Qt::AlignCenter); mainLayout->addWidget(displayLabel); @@ -59,6 +59,11 @@ void SelfCamView::showEvent(QShowEvent* event) void SelfCamView::updateDisplay() { - displayLabel->setPixmap(QPixmap::fromImage(cam->getLastImage())); + displayLabel->setPixmap(QPixmap::fromImage(cam->getLastImage()).scaled(displayLabel->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation)); } +void SelfCamView::resizeEvent(QResizeEvent *e) +{ + Q_UNUSED(e) + updateDisplay(); +} diff --git a/widget/selfcamview.h b/widget/selfcamview.h index a8cc29679..26a8b315c 100644 --- a/widget/selfcamview.h +++ b/widget/selfcamview.h @@ -42,6 +42,9 @@ private: void showEvent(QShowEvent*); void paint(QPainter *painter); +protected: + void resizeEvent(QResizeEvent *e); + private: QLabel *displayLabel; QHBoxLayout* mainLayout; From 59869b4a8771b3ddf14f789a67a544660bfdbf2a Mon Sep 17 00:00:00 2001 From: dubslow Date: Sat, 13 Sep 2014 00:55:21 -0500 Subject: [PATCH 035/205] first thing's first, gotta placate the ocd --- mainwindow.ui | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mainwindow.ui b/mainwindow.ui index 7f9cd12c5..20e8269cf 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -3124,13 +3124,13 @@ QSplitter:handle{ 0 - 60 + 57 16777215 - 60 + 57 From e4e36dc946027b603fcb60ff3791e7d6a6625907 Mon Sep 17 00:00:00 2001 From: dubslow Date: Sat, 13 Sep 2014 03:32:24 -0500 Subject: [PATCH 036/205] initial new settings widget, subforms not started also "filing" some files under misc --- core.cpp | 6 +- main.cpp | 2 +- cdata.cpp => misc/cdata.cpp | 0 cdata.h => misc/cdata.h | 0 cstring.cpp => misc/cstring.cpp | 0 cstring.h => misc/cstring.h | 0 settings.cpp => misc/settings.cpp | 0 settings.h => misc/settings.h | 0 smileypack.cpp => misc/smileypack.cpp | 0 smileypack.h => misc/smileypack.h | 0 style.cpp => misc/style.cpp | 0 style.h => misc/style.h | 0 qtox.pro | 28 ++--- widget/emoticonswidget.cpp | 4 +- widget/form/genericchatform.cpp | 6 +- widget/form/settingswidget.cpp | 164 ++++++++++++++++++++++++++ widget/form/settingswidget.h | 62 ++++++++++ widget/groupwidget.cpp | 2 +- widget/tool/chataction.cpp | 2 +- widget/widget.cpp | 11 +- widget/widget.h | 4 +- 21 files changed, 258 insertions(+), 33 deletions(-) rename cdata.cpp => misc/cdata.cpp (100%) rename cdata.h => misc/cdata.h (100%) rename cstring.cpp => misc/cstring.cpp (100%) rename cstring.h => misc/cstring.h (100%) rename settings.cpp => misc/settings.cpp (100%) rename settings.h => misc/settings.h (100%) rename smileypack.cpp => misc/smileypack.cpp (100%) rename smileypack.h => misc/smileypack.h (100%) rename style.cpp => misc/style.cpp (100%) rename style.h => misc/style.h (100%) create mode 100644 widget/form/settingswidget.cpp create mode 100644 widget/form/settingswidget.h diff --git a/core.cpp b/core.cpp index fe1e3187b..81d022588 100644 --- a/core.cpp +++ b/core.cpp @@ -15,9 +15,9 @@ */ #include "core.h" -#include "cdata.h" -#include "cstring.h" -#include "settings.h" +#include "misc/cdata.h" +#include "misc/cstring.h" +#include "misc/settings.h" #include "widget/widget.h" #include diff --git a/main.cpp b/main.cpp index 1cdac827e..8e981baa5 100644 --- a/main.cpp +++ b/main.cpp @@ -15,7 +15,7 @@ */ #include "widget/widget.h" -#include "settings.h" +#include "misc/settings.h" #include #include #include diff --git a/cdata.cpp b/misc/cdata.cpp similarity index 100% rename from cdata.cpp rename to misc/cdata.cpp diff --git a/cdata.h b/misc/cdata.h similarity index 100% rename from cdata.h rename to misc/cdata.h diff --git a/cstring.cpp b/misc/cstring.cpp similarity index 100% rename from cstring.cpp rename to misc/cstring.cpp diff --git a/cstring.h b/misc/cstring.h similarity index 100% rename from cstring.h rename to misc/cstring.h diff --git a/settings.cpp b/misc/settings.cpp similarity index 100% rename from settings.cpp rename to misc/settings.cpp diff --git a/settings.h b/misc/settings.h similarity index 100% rename from settings.h rename to misc/settings.h diff --git a/smileypack.cpp b/misc/smileypack.cpp similarity index 100% rename from smileypack.cpp rename to misc/smileypack.cpp diff --git a/smileypack.h b/misc/smileypack.h similarity index 100% rename from smileypack.h rename to misc/smileypack.h diff --git a/style.cpp b/misc/style.cpp similarity index 100% rename from style.cpp rename to misc/style.cpp diff --git a/style.h b/misc/style.h similarity index 100% rename from style.h rename to misc/style.h diff --git a/qtox.pro b/qtox.pro index 250d3abc8..9112e95c0 100644 --- a/qtox.pro +++ b/qtox.pro @@ -81,6 +81,7 @@ win32 { HEADERS += widget/form/addfriendform.h \ widget/form/chatform.h \ widget/form/groupchatform.h \ + widget/form/settingswidget.h \ widget/form/filesform.h \ widget/tool/chattextedit.h \ widget/tool/friendrequestdialog.h \ @@ -90,17 +91,17 @@ HEADERS += widget/form/addfriendform.h \ friend.h \ group.h \ grouplist.h \ - settings.h \ + misc/settings.h \ core.h \ friendlist.h \ - cdata.h \ - cstring.h \ + misc/cdata.h \ + misc/cstring.h \ widget/selfcamview.h \ widget/camera.h \ widget/netcamview.h \ - smileypack.h \ + misc/smileypack.h \ widget/emoticonswidget.h \ - style.h \ + misc/style.h \ widget/adjustingscrollarea.h \ widget/croppinglabel.h \ widget/friendlistwidget.h \ @@ -111,13 +112,13 @@ HEADERS += widget/form/addfriendform.h \ filetransferinstance.h \ corestructs.h \ coredefines.h \ - coreav.h \ - widget/settingsdialog.h + coreav.h SOURCES += \ widget/form/addfriendform.cpp \ widget/form/chatform.cpp \ widget/form/groupchatform.cpp \ + widget/form/settingswidget.cpp \ widget/form/filesform.cpp \ widget/tool/chattextedit.cpp \ widget/tool/friendrequestdialog.cpp \ @@ -130,15 +131,15 @@ SOURCES += \ group.cpp \ grouplist.cpp \ main.cpp \ - settings.cpp \ - cdata.cpp \ - cstring.cpp \ + misc/settings.cpp \ + misc/cdata.cpp \ + misc/cstring.cpp \ widget/selfcamview.cpp \ widget/camera.cpp \ widget/netcamview.cpp \ - smileypack.cpp \ + misc/smileypack.cpp \ widget/emoticonswidget.cpp \ - style.cpp \ + misc/style.cpp \ widget/adjustingscrollarea.cpp \ widget/croppinglabel.cpp \ widget/friendlistwidget.cpp \ @@ -148,5 +149,4 @@ SOURCES += \ widget/tool/chataction.cpp \ widget/chatareawidget.cpp \ filetransferinstance.cpp \ - corestructs.cpp \ - widget/settingsdialog.cpp + corestructs.cpp diff --git a/widget/emoticonswidget.cpp b/widget/emoticonswidget.cpp index bab7abe8d..b0ffb6028 100644 --- a/widget/emoticonswidget.cpp +++ b/widget/emoticonswidget.cpp @@ -15,8 +15,8 @@ */ #include "emoticonswidget.h" -#include "smileypack.h" -#include "style.h" +#include "misc/smileypack.h" +#include "misc/style.h" #include #include diff --git a/widget/form/genericchatform.cpp b/widget/form/genericchatform.cpp index f5681f1c6..2aff5d2a7 100644 --- a/widget/form/genericchatform.cpp +++ b/widget/form/genericchatform.cpp @@ -17,11 +17,11 @@ #include "genericchatform.h" #include "ui_mainwindow.h" #include -#include "smileypack.h" +#include "misc/smileypack.h" #include "widget/emoticonswidget.h" -#include "style.h" +#include "misc/style.h" #include "widget/widget.h" -#include "settings.h" +#include "misc/settings.h" #include "widget/tool/chataction.h" #include "widget/chatareawidget.h" #include "widget/tool/chattextedit.h" diff --git a/widget/form/settingswidget.cpp b/widget/form/settingswidget.cpp new file mode 100644 index 000000000..6e2778de8 --- /dev/null +++ b/widget/form/settingswidget.cpp @@ -0,0 +1,164 @@ +/* + Copyright (C) 2014 by Project Tox + + This file is part of qTox, a Qt-based graphical interface for Tox. + + This program 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. + 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 COPYING file for more details. +*/ + +#include "settingswidget.h" +#include "widget/widget.h" +#include "ui_mainwindow.h" + +SettingsWidget::SettingsWidget() + : QObject() +{ + main = new QWidget(); + // this crap is copied from ui_mainwindow.h... there's no easy way around + // just straight up copying it like this... oh well + // the layout/icons obviously need to be improved, but it's a working model, + // not a pretty one + QSizePolicy sizePolicy3(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); + sizePolicy3.setHorizontalStretch(0); + sizePolicy3.setVerticalStretch(0); + head = new QWidget(); + head->setObjectName(QStringLiteral("head")); + head->setEnabled(true); + sizePolicy3.setHeightForWidth(head->sizePolicy().hasHeightForWidth()); + head->setSizePolicy(sizePolicy3); + QPalette palette5; + QBrush brush(QColor(255, 255, 255, 255)); + brush.setStyle(Qt::SolidPattern); + QBrush brush1(QColor(28, 28, 28, 255)); + brush1.setStyle(Qt::SolidPattern); + QBrush brush2(QColor(42, 42, 42, 255)); + brush2.setStyle(Qt::SolidPattern); + QBrush brush3(QColor(35, 35, 35, 255)); + brush3.setStyle(Qt::SolidPattern); + QBrush brush4(QColor(14, 14, 14, 255)); + brush4.setStyle(Qt::SolidPattern); + QBrush brush5(QColor(18, 18, 18, 255)); + brush5.setStyle(Qt::SolidPattern); + QBrush brush6(QColor(0, 0, 0, 255)); + brush6.setStyle(Qt::SolidPattern); + QBrush brush7(QColor(255, 255, 220, 255)); + brush7.setStyle(Qt::SolidPattern); + palette5.setBrush(QPalette::Active, QPalette::WindowText, brush); + palette5.setBrush(QPalette::Active, QPalette::Button, brush1); + palette5.setBrush(QPalette::Active, QPalette::Light, brush2); + palette5.setBrush(QPalette::Active, QPalette::Midlight, brush3); + palette5.setBrush(QPalette::Active, QPalette::Dark, brush4); + palette5.setBrush(QPalette::Active, QPalette::Mid, brush5); + palette5.setBrush(QPalette::Active, QPalette::Text, brush); + palette5.setBrush(QPalette::Active, QPalette::BrightText, brush); + palette5.setBrush(QPalette::Active, QPalette::ButtonText, brush); + palette5.setBrush(QPalette::Active, QPalette::Base, brush6); + palette5.setBrush(QPalette::Active, QPalette::Window, brush1); + palette5.setBrush(QPalette::Active, QPalette::Shadow, brush6); + palette5.setBrush(QPalette::Active, QPalette::AlternateBase, brush4); + palette5.setBrush(QPalette::Active, QPalette::ToolTipBase, brush7); + palette5.setBrush(QPalette::Active, QPalette::ToolTipText, brush6); + palette5.setBrush(QPalette::Inactive, QPalette::WindowText, brush); + palette5.setBrush(QPalette::Inactive, QPalette::Button, brush1); + palette5.setBrush(QPalette::Inactive, QPalette::Light, brush2); + palette5.setBrush(QPalette::Inactive, QPalette::Midlight, brush3); + palette5.setBrush(QPalette::Inactive, QPalette::Dark, brush4); + palette5.setBrush(QPalette::Inactive, QPalette::Mid, brush5); + palette5.setBrush(QPalette::Inactive, QPalette::Text, brush); + palette5.setBrush(QPalette::Inactive, QPalette::BrightText, brush); + palette5.setBrush(QPalette::Inactive, QPalette::ButtonText, brush); + palette5.setBrush(QPalette::Inactive, QPalette::Base, brush6); + palette5.setBrush(QPalette::Inactive, QPalette::Window, brush1); + palette5.setBrush(QPalette::Inactive, QPalette::Shadow, brush6); + palette5.setBrush(QPalette::Inactive, QPalette::AlternateBase, brush4); + palette5.setBrush(QPalette::Inactive, QPalette::ToolTipBase, brush7); + palette5.setBrush(QPalette::Inactive, QPalette::ToolTipText, brush6); + palette5.setBrush(QPalette::Disabled, QPalette::WindowText, brush4); + palette5.setBrush(QPalette::Disabled, QPalette::Button, brush1); + palette5.setBrush(QPalette::Disabled, QPalette::Light, brush2); + palette5.setBrush(QPalette::Disabled, QPalette::Midlight, brush3); + palette5.setBrush(QPalette::Disabled, QPalette::Dark, brush4); + palette5.setBrush(QPalette::Disabled, QPalette::Mid, brush5); + palette5.setBrush(QPalette::Disabled, QPalette::Text, brush4); + palette5.setBrush(QPalette::Disabled, QPalette::BrightText, brush); + palette5.setBrush(QPalette::Disabled, QPalette::ButtonText, brush4); + palette5.setBrush(QPalette::Disabled, QPalette::Base, brush1); + palette5.setBrush(QPalette::Disabled, QPalette::Window, brush1); + palette5.setBrush(QPalette::Disabled, QPalette::Shadow, brush6); + palette5.setBrush(QPalette::Disabled, QPalette::AlternateBase, brush1); + palette5.setBrush(QPalette::Disabled, QPalette::ToolTipBase, brush7); + palette5.setBrush(QPalette::Disabled, QPalette::ToolTipText, brush6); + head->setPalette(palette5); + head->setAutoFillBackground(true); + iconsLayout = new QHBoxLayout(head); + iconsLayout->setSpacing(0); + iconsLayout->setObjectName(QStringLiteral("iconsLayout")); + iconsLayout->setContentsMargins(0, 0, 0, 0); + + generalButton = new QPushButton(head); + generalButton->setObjectName(QStringLiteral("generalButton")); + generalButton->setMinimumSize(QSize(55, 35)); + generalButton->setMaximumSize(QSize(55, 35)); + generalButton->setFocusPolicy(Qt::NoFocus); + QIcon icon1; + icon1.addFile(QStringLiteral(":/img/add.png"), QSize(), QIcon::Normal, QIcon::Off); + generalButton->setIcon(icon1); + generalButton->setFlat(true); + iconsLayout->addWidget(generalButton); + + identityButton = new QPushButton(head); + identityButton->setObjectName(QStringLiteral("identityButton")); + identityButton->setMinimumSize(QSize(55, 35)); + identityButton->setMaximumSize(QSize(55, 35)); + identityButton->setFocusPolicy(Qt::NoFocus); + QIcon icon2; + icon2.addFile(QStringLiteral(":/img/group.png"), QSize(), QIcon::Normal, QIcon::Off); + identityButton->setIcon(icon2); + identityButton->setFlat(true); + iconsLayout->addWidget(identityButton); + + privacyButton = new QPushButton(head); + privacyButton->setObjectName(QStringLiteral("privacyButton")); + privacyButton->setMinimumSize(QSize(55, 35)); + privacyButton->setMaximumSize(QSize(55, 35)); + privacyButton->setFocusPolicy(Qt::NoFocus); + QIcon icon3; + icon3.addFile(QStringLiteral(":/img/transfer.png"), QSize(), QIcon::Normal, QIcon::Off); + privacyButton->setIcon(icon3); + privacyButton->setFlat(true); + iconsLayout->addWidget(privacyButton); + + avButton = new QPushButton(head); + avButton->setObjectName(QStringLiteral("avButton")); + avButton->setMinimumSize(QSize(55, 35)); + avButton->setMaximumSize(QSize(55, 35)); + avButton->setFocusPolicy(Qt::NoFocus); + QIcon icon4; + icon4.addFile(QStringLiteral(":/img/settings.png"), QSize(), QIcon::Normal, QIcon::Off); + avButton->setIcon(icon4); + avButton->setFlat(true); + iconsLayout->addWidget(avButton); + + head->setLayout(iconsLayout); + +} + +SettingsWidget::~SettingsWidget() +{ +} + +void SettingsWidget::show(Ui::MainWindow& ui) +{ + ui.mainContent->layout()->addWidget(main); + ui.mainHead->layout()->addWidget(head); + main->show(); + head->show(); +} diff --git a/widget/form/settingswidget.h b/widget/form/settingswidget.h new file mode 100644 index 000000000..a1cee909f --- /dev/null +++ b/widget/form/settingswidget.h @@ -0,0 +1,62 @@ +/* + Copyright (C) 2014 by Project Tox + + This file is part of qTox, a Qt-based graphical interface for Tox. + + This program 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. + 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 COPYING file for more details. +*/ + +#ifndef SETTINGSWIDGET_H +#define SETTINGSWIDGET_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "widget/croppinglabel.h" + +namespace Ui {class MainWindow;} +class QString; + +class SettingsWidget : public QObject +{ + Q_OBJECT +public: + SettingsWidget(); + ~SettingsWidget(); + + void show(Ui::MainWindow &ui); + +public slots: + //void setFriendAddress(const QString& friendAddress); + +private slots: + +private: + QWidget *main, *head; + // the code pertaining to the icons is mostly copied from ui_mainwindow.h + QHBoxLayout *iconsLayout; + QPushButton *generalButton; + QPushButton *identityButton; + QPushButton *privacyButton; + QPushButton *avButton; + + // now the actual pages and stuff + // ... +public: +}; + +#endif // SETTINGSFORM_H diff --git a/widget/groupwidget.cpp b/widget/groupwidget.cpp index b8c1cbcc0..0c02db3d2 100644 --- a/widget/groupwidget.cpp +++ b/widget/groupwidget.cpp @@ -17,7 +17,7 @@ #include "groupwidget.h" #include "grouplist.h" #include "group.h" -#include "settings.h" +#include "misc/settings.h" #include "widget/form/groupchatform.h" #include #include diff --git a/widget/tool/chataction.cpp b/widget/tool/chataction.cpp index bcd1f1080..c05fd36b9 100644 --- a/widget/tool/chataction.cpp +++ b/widget/tool/chataction.cpp @@ -15,7 +15,7 @@ */ #include "chataction.h" -#include "smileypack.h" +#include "misc/smileypack.h" #include #include #include "filetransferinstance.h" diff --git a/widget/widget.cpp b/widget/widget.cpp index 36b2c33c1..f1472bcd6 100644 --- a/widget/widget.cpp +++ b/widget/widget.cpp @@ -17,7 +17,7 @@ #include "widget.h" #include "ui_mainwindow.h" #include "core.h" -#include "settings.h" +#include "misc/settings.h" #include "friend.h" #include "friendlist.h" #include "widget/tool/friendrequestdialog.h" @@ -26,12 +26,11 @@ #include "group.h" #include "widget/groupwidget.h" #include "widget/form/groupchatform.h" -#include "style.h" +#include "misc/style.h" #include "selfcamview.h" #include "widget/friendlistwidget.h" #include "camera.h" #include "widget/form/chatform.h" -#include "widget/settingsdialog.h" #include #include #include @@ -156,7 +155,6 @@ Widget::Widget(QWidget *parent) ui->statusButton->style()->polish(ui->statusButton); camera = new Camera; - settingsDialog = new SettingsDialog(this); // Disable some widgets until we're connected to the DHT ui->statusButton->setEnabled(false); @@ -335,8 +333,9 @@ void Widget::onTransferClicked() void Widget::onSettingsClicked() { - settingsDialog->readConfig(); - settingsDialog->show(); + hideMainForms(); + settingsWidget.show(*ui); + activeChatroomWidget = nullptr; } void Widget::hideMainForms() diff --git a/widget/widget.h b/widget/widget.h index 035ea2ae0..9512f00e9 100644 --- a/widget/widget.h +++ b/widget/widget.h @@ -19,6 +19,7 @@ #include #include "widget/form/addfriendform.h" +#include "widget/form/settingswidget.h" #include "widget/form/filesform.h" #include "corestructs.h" @@ -37,7 +38,6 @@ class QMenu; class Core; class Camera; class FriendListWidget; -class SettingsDialog; class Widget : public QMainWindow { @@ -134,8 +134,8 @@ private: Core* core; QThread* coreThread; AddFriendForm friendForm; + SettingsWidget settingsWidget; FilesForm filesForm; - SettingsDialog* settingsDialog; static Widget* instance; GenericChatroomWidget* activeChatroomWidget; FriendListWidget* contactListWidget; From e55f15725ec9558bdca588c8a2cfe80f40fef5b7 Mon Sep 17 00:00:00 2001 From: bill Date: Sun, 14 Sep 2014 13:42:27 -0500 Subject: [PATCH 037/205] move buttons to bottom --- widget/form/settingswidget.cpp | 66 +++++++++++++++++++--------------- widget/form/settingswidget.h | 20 +++++------ 2 files changed, 48 insertions(+), 38 deletions(-) diff --git a/widget/form/settingswidget.cpp b/widget/form/settingswidget.cpp index 6e2778de8..fcbd2a981 100644 --- a/widget/form/settingswidget.cpp +++ b/widget/form/settingswidget.cpp @@ -19,9 +19,35 @@ #include "ui_mainwindow.h" SettingsWidget::SettingsWidget() - : QObject() + : QWidget() { + _main = new QWidget(); main = new QWidget(); + head = new QWidget(); + foot = new QWidget(); + prepButtons(); + foot->setLayout(iconsLayout); + _mainLayout = new QVBoxLayout(_main); + _mainLayout->addWidget(main); + _mainLayout->addWidget(foot); + // something something foot size + _main->setLayout(_mainLayout); +} + +SettingsWidget::~SettingsWidget() +{ +} + +void SettingsWidget::show(Ui::MainWindow& ui) +{ + ui.mainContent->layout()->addWidget(_main); + ui.mainHead->layout()->addWidget(head); + _main->show(); + head->show(); +} + +void SettingsWidget::prepButtons() +{ // this crap is copied from ui_mainwindow.h... there's no easy way around // just straight up copying it like this... oh well // the layout/icons obviously need to be improved, but it's a working model, @@ -29,11 +55,9 @@ SettingsWidget::SettingsWidget() QSizePolicy sizePolicy3(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); sizePolicy3.setHorizontalStretch(0); sizePolicy3.setVerticalStretch(0); - head = new QWidget(); - head->setObjectName(QStringLiteral("head")); - head->setEnabled(true); - sizePolicy3.setHeightForWidth(head->sizePolicy().hasHeightForWidth()); - head->setSizePolicy(sizePolicy3); + foot->setObjectName(QStringLiteral("foot")); + foot->setEnabled(true); + foot->setSizePolicy(sizePolicy3); QPalette palette5; QBrush brush(QColor(255, 255, 255, 255)); brush.setStyle(Qt::SolidPattern); @@ -96,14 +120,15 @@ SettingsWidget::SettingsWidget() palette5.setBrush(QPalette::Disabled, QPalette::AlternateBase, brush1); palette5.setBrush(QPalette::Disabled, QPalette::ToolTipBase, brush7); palette5.setBrush(QPalette::Disabled, QPalette::ToolTipText, brush6); - head->setPalette(palette5); - head->setAutoFillBackground(true); - iconsLayout = new QHBoxLayout(head); + foot->setPalette(palette5); + foot->setAutoFillBackground(true); + + iconsLayout = new QHBoxLayout(foot); iconsLayout->setSpacing(0); iconsLayout->setObjectName(QStringLiteral("iconsLayout")); iconsLayout->setContentsMargins(0, 0, 0, 0); - generalButton = new QPushButton(head); + generalButton = new QPushButton(foot); generalButton->setObjectName(QStringLiteral("generalButton")); generalButton->setMinimumSize(QSize(55, 35)); generalButton->setMaximumSize(QSize(55, 35)); @@ -114,7 +139,7 @@ SettingsWidget::SettingsWidget() generalButton->setFlat(true); iconsLayout->addWidget(generalButton); - identityButton = new QPushButton(head); + identityButton = new QPushButton(foot); identityButton->setObjectName(QStringLiteral("identityButton")); identityButton->setMinimumSize(QSize(55, 35)); identityButton->setMaximumSize(QSize(55, 35)); @@ -125,7 +150,7 @@ SettingsWidget::SettingsWidget() identityButton->setFlat(true); iconsLayout->addWidget(identityButton); - privacyButton = new QPushButton(head); + privacyButton = new QPushButton(foot); privacyButton->setObjectName(QStringLiteral("privacyButton")); privacyButton->setMinimumSize(QSize(55, 35)); privacyButton->setMaximumSize(QSize(55, 35)); @@ -136,7 +161,7 @@ SettingsWidget::SettingsWidget() privacyButton->setFlat(true); iconsLayout->addWidget(privacyButton); - avButton = new QPushButton(head); + avButton = new QPushButton(foot); avButton->setObjectName(QStringLiteral("avButton")); avButton->setMinimumSize(QSize(55, 35)); avButton->setMaximumSize(QSize(55, 35)); @@ -146,19 +171,4 @@ SettingsWidget::SettingsWidget() avButton->setIcon(icon4); avButton->setFlat(true); iconsLayout->addWidget(avButton); - - head->setLayout(iconsLayout); - -} - -SettingsWidget::~SettingsWidget() -{ -} - -void SettingsWidget::show(Ui::MainWindow& ui) -{ - ui.mainContent->layout()->addWidget(main); - ui.mainHead->layout()->addWidget(head); - main->show(); - head->show(); } diff --git a/widget/form/settingswidget.h b/widget/form/settingswidget.h index a1cee909f..c901ce906 100644 --- a/widget/form/settingswidget.h +++ b/widget/form/settingswidget.h @@ -17,21 +17,15 @@ #ifndef SETTINGSWIDGET_H #define SETTINGSWIDGET_H -#include -#include -#include -#include -#include +#include #include -#include -#include - +#include #include "widget/croppinglabel.h" namespace Ui {class MainWindow;} class QString; -class SettingsWidget : public QObject +class SettingsWidget : public QWidget { Q_OBJECT public: @@ -46,7 +40,9 @@ public slots: private slots: private: - QWidget *main, *head; + QWidget *_main, *main, *head, *foot; + // _main consists of main+foot + QVBoxLayout *_mainLayout; // the code pertaining to the icons is mostly copied from ui_mainwindow.h QHBoxLayout *iconsLayout; QPushButton *generalButton; @@ -56,6 +52,10 @@ private: // now the actual pages and stuff // ... + + + + void prepButtons(); // just so I can move the crap to the bottom of the file public: }; From 5ec79fc26080eae03350877686336d1caba223a2 Mon Sep 17 00:00:00 2001 From: bill Date: Mon, 15 Sep 2014 05:45:59 -0500 Subject: [PATCH 038/205] new settings infrastructure done, though there's a double free or something in ~Widget() --- qtox.pro | 9 ++++ widget/form/settings/avform.cpp | 26 ++++++++++ widget/form/settings/avform.h | 33 ++++++++++++ widget/form/settings/generalform.cpp | 46 ++++++++++++++++ widget/form/settings/generalform.h | 41 +++++++++++++++ widget/form/settings/genericsettings.h | 46 ++++++++++++++++ widget/form/settings/identityform.cpp | 38 ++++++++++++++ widget/form/settings/identityform.h | 34 ++++++++++++ widget/form/settings/privacyform.cpp | 27 ++++++++++ widget/form/settings/privacyform.h | 33 ++++++++++++ widget/form/settingswidget.cpp | 72 +++++++++++++++++++++++--- widget/form/settingswidget.h | 41 +++++++++------ 12 files changed, 423 insertions(+), 23 deletions(-) create mode 100644 widget/form/settings/avform.cpp create mode 100644 widget/form/settings/avform.h create mode 100644 widget/form/settings/generalform.cpp create mode 100644 widget/form/settings/generalform.h create mode 100644 widget/form/settings/genericsettings.h create mode 100644 widget/form/settings/identityform.cpp create mode 100644 widget/form/settings/identityform.h create mode 100644 widget/form/settings/privacyform.cpp create mode 100644 widget/form/settings/privacyform.h diff --git a/qtox.pro b/qtox.pro index 9112e95c0..5c550cd1f 100644 --- a/qtox.pro +++ b/qtox.pro @@ -82,6 +82,11 @@ HEADERS += widget/form/addfriendform.h \ widget/form/chatform.h \ widget/form/groupchatform.h \ widget/form/settingswidget.h \ + widget/form/settings/genericsettings.h \ + widget/form/settings/generalform.h \ + widget/form/settings/identityform.h \ + widget/form/settings/privacyform.h \ + widget/form/settings/avform.h \ widget/form/filesform.h \ widget/tool/chattextedit.h \ widget/tool/friendrequestdialog.h \ @@ -119,6 +124,10 @@ SOURCES += \ widget/form/chatform.cpp \ widget/form/groupchatform.cpp \ widget/form/settingswidget.cpp \ + widget/form/settings/generalform.cpp \ + widget/form/settings/identityform.cpp \ + widget/form/settings/privacyform.cpp \ + widget/form/settings/avform.cpp \ widget/form/filesform.cpp \ widget/tool/chattextedit.cpp \ widget/tool/friendrequestdialog.cpp \ diff --git a/widget/form/settings/avform.cpp b/widget/form/settings/avform.cpp new file mode 100644 index 000000000..347a1cfbb --- /dev/null +++ b/widget/form/settings/avform.cpp @@ -0,0 +1,26 @@ +/* + Copyright (C) 2014 by Project Tox + + This file is part of qTox, a Qt-based graphical interface for Tox. + + This program 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. + 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 COPYING file for more details. +*/ + +#include "avform.h" + +AVForm::AVForm() +{ + prep(); +} + +AVForm::~AVForm() +{ +} diff --git a/widget/form/settings/avform.h b/widget/form/settings/avform.h new file mode 100644 index 000000000..e214e133e --- /dev/null +++ b/widget/form/settings/avform.h @@ -0,0 +1,33 @@ +/* + Copyright (C) 2014 by Project Tox + + This file is part of qTox, a Qt-based graphical interface for Tox. + + This program 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. + 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 COPYING file for more details. +*/ + +#ifndef AVFORM_H +#define AVFORM_H + +#include "genericsettings.h" + +class AVForm : public GenericForm +{ + Q_OBJECT +public: + AVForm(); + ~AVForm(); + +private: + +}; + +#endif diff --git a/widget/form/settings/generalform.cpp b/widget/form/settings/generalform.cpp new file mode 100644 index 000000000..050d4f7eb --- /dev/null +++ b/widget/form/settings/generalform.cpp @@ -0,0 +1,46 @@ +/* + Copyright (C) 2014 by Project Tox + + This file is part of qTox, a Qt-based graphical interface for Tox. + + This program 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. + 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 COPYING file for more details. +*/ + +#include "generalform.h" +#include "widget/form/settingswidget.h" + +GeneralForm::GeneralForm() +{ + prep(); + group = new QGroupBox(tr("General Settings")); + enableIPv6 = new QCheckBox(); + enableIPv6->setText(tr("Enable IPv6 (recommended)","Text on a checkbox to enable IPv6")); + useTranslations = new QCheckBox(); + useTranslations->setText(tr("Use translations","Text on a checkbox to enable translations")); + makeToxPortable = new QCheckBox(); + makeToxPortable->setText(tr("Make Tox portable","Text on a checkbox to make qTox a portable application")); + makeToxPortable->setToolTip(tr("Save settings to the working directory instead of the usual conf dir","describes makeToxPortable checkbox")); + + QVBoxLayout *vLayout = new QVBoxLayout(); + vLayout->addWidget(enableIPv6); + vLayout->addWidget(useTranslations); + vLayout->addWidget(makeToxPortable); + group->setLayout(vLayout); + + label.setText(tr("General Settings")); + + headLayout.addWidget(&label); + layout.addWidget(group); +} + +GeneralForm::~GeneralForm() +{ +} diff --git a/widget/form/settings/generalform.h b/widget/form/settings/generalform.h new file mode 100644 index 000000000..c484a436d --- /dev/null +++ b/widget/form/settings/generalform.h @@ -0,0 +1,41 @@ +/* + Copyright (C) 2014 by Project Tox + + This file is part of qTox, a Qt-based graphical interface for Tox. + + This program 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. + 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 COPYING file for more details. +*/ + +#ifndef GENERALFORM_H +#define GENERALFORM_H + +#include "genericsettings.h" +#include +#include +#include + + +class GeneralForm : public GenericForm +{ + Q_OBJECT +public: + GeneralForm(); + ~GeneralForm(); + +private: + QGroupBox *group; + QCheckBox* enableIPv6; + QCheckBox* useTranslations; + QCheckBox* makeToxPortable; + QLabel label; +}; + +#endif diff --git a/widget/form/settings/genericsettings.h b/widget/form/settings/genericsettings.h new file mode 100644 index 000000000..9353d21df --- /dev/null +++ b/widget/form/settings/genericsettings.h @@ -0,0 +1,46 @@ +/* + Copyright (C) 2014 by Project Tox + + This file is part of qTox, a Qt-based graphical interface for Tox. + + This program 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. + 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 COPYING file for more details. +*/ + +#ifndef GENERICFORM_H +#define GENERICFORM_H + +#include +#include +#include "widget/form/settingswidget.h" + +class GenericForm : public QObject +{ + Q_OBJECT +public: + virtual void show(SettingsWidget& sw) + { + sw.body->layout()->addWidget(&body); + body.show(); + sw.head->layout()->addWidget(&head); + head.show(); + } + +protected: + QVBoxLayout layout, headLayout; + QWidget head, body; + void prep() // call in subclass constructor + { + head.setLayout(&headLayout); + body.setLayout(&layout); + } +}; + +#endif diff --git a/widget/form/settings/identityform.cpp b/widget/form/settings/identityform.cpp new file mode 100644 index 000000000..dbd5574c5 --- /dev/null +++ b/widget/form/settings/identityform.cpp @@ -0,0 +1,38 @@ +/* + Copyright (C) 2014 by Project Tox + + This file is part of qTox, a Qt-based graphical interface for Tox. + + This program 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. + 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 COPYING file for more details. +*/ + +#include "identityform.h" +#include "widget/form/settingswidget.h" +#include +#include + +IdentityForm::IdentityForm() +{ + prep(); + toxGroup = new QGroupBox(tr("Tox ID")); + QLabel* toxIdLabel = new QLabel(tr("Your Tox ID")); + QLineEdit* toxID = new QLineEdit(); + toxID->setReadOnly(true); + QVBoxLayout* toxLayout = new QVBoxLayout(); + toxLayout->addWidget(toxIdLabel); + toxLayout->addWidget(toxID); + toxGroup->setLayout(toxLayout); + layout.addWidget(toxGroup); +} + +IdentityForm::~IdentityForm() +{ +} diff --git a/widget/form/settings/identityform.h b/widget/form/settings/identityform.h new file mode 100644 index 000000000..dc616d75e --- /dev/null +++ b/widget/form/settings/identityform.h @@ -0,0 +1,34 @@ +/* + Copyright (C) 2014 by Project Tox + + This file is part of qTox, a Qt-based graphical interface for Tox. + + This program 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. + 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 COPYING file for more details. +*/ + +#ifndef IDENTITYFORM_H +#define IDENTITYFORM_H + +#include "genericsettings.h" +#include + +class IdentityForm : public GenericForm +{ + Q_OBJECT +public: + IdentityForm(); + ~IdentityForm(); + +private: + QGroupBox* toxGroup; +}; + +#endif diff --git a/widget/form/settings/privacyform.cpp b/widget/form/settings/privacyform.cpp new file mode 100644 index 000000000..856f64954 --- /dev/null +++ b/widget/form/settings/privacyform.cpp @@ -0,0 +1,27 @@ +/* + Copyright (C) 2014 by Project Tox + + This file is part of qTox, a Qt-based graphical interface for Tox. + + This program 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. + 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 COPYING file for more details. +*/ + +#include "privacyform.h" +#include "widget/form/settingswidget.h" + +PrivacyForm::PrivacyForm() +{ + prep(); +} + +PrivacyForm::~PrivacyForm() +{ +} diff --git a/widget/form/settings/privacyform.h b/widget/form/settings/privacyform.h new file mode 100644 index 000000000..ae1e61956 --- /dev/null +++ b/widget/form/settings/privacyform.h @@ -0,0 +1,33 @@ +/* + Copyright (C) 2014 by Project Tox + + This file is part of qTox, a Qt-based graphical interface for Tox. + + This program 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. + 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 COPYING file for more details. +*/ + +#ifndef PRIVACYFORM_H +#define PRIVACYFORM_H + +#include "genericsettings.h" + +class PrivacyForm : public GenericForm +{ + Q_OBJECT +public: + PrivacyForm(); + ~PrivacyForm(); + +private: + +}; + +#endif diff --git a/widget/form/settingswidget.cpp b/widget/form/settingswidget.cpp index fcbd2a981..3a13c1cdb 100644 --- a/widget/form/settingswidget.cpp +++ b/widget/form/settingswidget.cpp @@ -17,21 +17,41 @@ #include "settingswidget.h" #include "widget/widget.h" #include "ui_mainwindow.h" +#include "widget/form/settings/generalform.h" +#include "widget/form/settings/identityform.h" +#include "widget/form/settings/privacyform.h" +#include "widget/form/settings/avform.h" SettingsWidget::SettingsWidget() : QWidget() { - _main = new QWidget(); + generalForm = new GeneralForm(); + identityForm = new IdentityForm(); + privacyForm = new PrivacyForm(); + avForm = new AVForm(); + main = new QWidget(); + body = new QWidget(); head = new QWidget(); foot = new QWidget(); + + head->setLayout(new QVBoxLayout()); + body->setLayout(new QVBoxLayout()); + prepButtons(); foot->setLayout(iconsLayout); - _mainLayout = new QVBoxLayout(_main); - _mainLayout->addWidget(main); - _mainLayout->addWidget(foot); + mainLayout = new QVBoxLayout(main); + mainLayout->addWidget(body); + mainLayout->addWidget(foot); // something something foot size - _main->setLayout(_mainLayout); + main->setLayout(mainLayout); + + connect(generalButton, &QPushButton::clicked, this, &SettingsWidget::onGeneralClicked); + connect(identityButton, &QPushButton::clicked, this, &SettingsWidget::onIdentityClicked); + connect(privacyButton, &QPushButton::clicked, this, &SettingsWidget::onPrivacyClicked); + connect(avButton, &QPushButton::clicked, this, &SettingsWidget::onAVClicked); + + active = generalForm; } SettingsWidget::~SettingsWidget() @@ -40,12 +60,50 @@ SettingsWidget::~SettingsWidget() void SettingsWidget::show(Ui::MainWindow& ui) { - ui.mainContent->layout()->addWidget(_main); + active->show(*this); + ui.mainContent->layout()->addWidget(main); ui.mainHead->layout()->addWidget(head); - _main->show(); + main->show(); head->show(); } +void SettingsWidget::onGeneralClicked() +{ + hideSettingsForms(); + active = generalForm; + generalForm->show(*this); +} + +void SettingsWidget::onIdentityClicked() +{ + hideSettingsForms(); + active = identityForm; + identityForm->show(*this); +} + +void SettingsWidget::onPrivacyClicked() +{ + hideSettingsForms(); + active = privacyForm; + privacyForm->show(*this); +} + +void SettingsWidget::onAVClicked() +{ + hideSettingsForms(); + active = avForm; + avForm->show(*this); +} + +void SettingsWidget::hideSettingsForms() +{ + QLayoutItem *item; + while ((item = head->layout()->takeAt(0)) != 0) + item->widget()->hide(); + while ((item = body->layout()->takeAt(0)) != 0) + item->widget()->hide(); +} + void SettingsWidget::prepButtons() { // this crap is copied from ui_mainwindow.h... there's no easy way around diff --git a/widget/form/settingswidget.h b/widget/form/settingswidget.h index c901ce906..6ee45f90d 100644 --- a/widget/form/settingswidget.h +++ b/widget/form/settingswidget.h @@ -19,11 +19,12 @@ #include #include -#include -#include "widget/croppinglabel.h" - -namespace Ui {class MainWindow;} -class QString; +class GenericForm; +class GeneralForm; +class IdentityForm; +class PrivacyForm; +class AVForm; +namespace Ui {class MainWindow;}; class SettingsWidget : public QWidget { @@ -33,30 +34,38 @@ public: ~SettingsWidget(); void show(Ui::MainWindow &ui); + + QWidget *head, *body; // keep the others private public slots: //void setFriendAddress(const QString& friendAddress); private slots: + void onGeneralClicked(); + void onIdentityClicked(); + void onPrivacyClicked(); + void onAVClicked(); private: - QWidget *_main, *main, *head, *foot; - // _main consists of main+foot - QVBoxLayout *_mainLayout; + QWidget *main, *foot; + // main consists of body+foot for Ui::MainWindow + QVBoxLayout *mainLayout; + + GenericForm* active; + GeneralForm* generalForm; + IdentityForm* identityForm; + PrivacyForm* privacyForm; + AVForm* avForm; + void hideSettingsForms(); + + // the code pertaining to the icons is mostly copied from ui_mainwindow.h QHBoxLayout *iconsLayout; QPushButton *generalButton; QPushButton *identityButton; QPushButton *privacyButton; QPushButton *avButton; - - // now the actual pages and stuff - // ... - - - void prepButtons(); // just so I can move the crap to the bottom of the file -public: }; -#endif // SETTINGSFORM_H +#endif // SETTINGSWIDGET_H From 575862f25f1b0f5b18ff4c2698c572a590d26277 Mon Sep 17 00:00:00 2001 From: dubslow Date: Mon, 15 Sep 2014 08:31:42 -0500 Subject: [PATCH 039/205] cosmetics --- widget/form/settings/avform.cpp | 2 ++ widget/form/settings/generalform.cpp | 2 ++ widget/form/settings/genericsettings.h | 8 +++++++- widget/form/settings/identityform.cpp | 2 ++ widget/form/settings/privacyform.cpp | 2 ++ widget/form/settingswidget.cpp | 2 +- 6 files changed, 16 insertions(+), 2 deletions(-) diff --git a/widget/form/settings/avform.cpp b/widget/form/settings/avform.cpp index 347a1cfbb..5c0b38da3 100644 --- a/widget/form/settings/avform.cpp +++ b/widget/form/settings/avform.cpp @@ -19,6 +19,8 @@ AVForm::AVForm() { prep(); + icon.addFile(":/img/settings/av.png"); + label.setText(tr("Audio/Video settings")); } AVForm::~AVForm() diff --git a/widget/form/settings/generalform.cpp b/widget/form/settings/generalform.cpp index 050d4f7eb..a9810c1ae 100644 --- a/widget/form/settings/generalform.cpp +++ b/widget/form/settings/generalform.cpp @@ -20,6 +20,8 @@ GeneralForm::GeneralForm() { prep(); + icon.addFile(":/img/settings/general.png"); + label.setText(tr("General settings")); group = new QGroupBox(tr("General Settings")); enableIPv6 = new QCheckBox(); enableIPv6->setText(tr("Enable IPv6 (recommended)","Text on a checkbox to enable IPv6")); diff --git a/widget/form/settings/genericsettings.h b/widget/form/settings/genericsettings.h index 9353d21df..94f8fe90f 100644 --- a/widget/form/settings/genericsettings.h +++ b/widget/form/settings/genericsettings.h @@ -34,13 +34,19 @@ public: } protected: - QVBoxLayout layout, headLayout; + QVBoxLayout layout; + QHBoxLayout headLayout; + QIcon icon; + QLabel label; QWidget head, body; void prep() // call in subclass constructor { head.setLayout(&headLayout); + headLayout.addWidget(&icon); + headLayout.addWidget(&label); body.setLayout(&layout); } + }; #endif diff --git a/widget/form/settings/identityform.cpp b/widget/form/settings/identityform.cpp index dbd5574c5..ac89257a9 100644 --- a/widget/form/settings/identityform.cpp +++ b/widget/form/settings/identityform.cpp @@ -22,6 +22,8 @@ IdentityForm::IdentityForm() { prep(); + icon.addFile(":/img/settings/identity.png"); + label.setText(tr("Your identity")); toxGroup = new QGroupBox(tr("Tox ID")); QLabel* toxIdLabel = new QLabel(tr("Your Tox ID")); QLineEdit* toxID = new QLineEdit(); diff --git a/widget/form/settings/privacyform.cpp b/widget/form/settings/privacyform.cpp index 856f64954..ef7c54c4b 100644 --- a/widget/form/settings/privacyform.cpp +++ b/widget/form/settings/privacyform.cpp @@ -20,6 +20,8 @@ PrivacyForm::PrivacyForm() { prep(); + icon.addFile(":/img/settings/privacy.png"); + label.setText(tr("Privacy settings")); } PrivacyForm::~PrivacyForm() diff --git a/widget/form/settingswidget.cpp b/widget/form/settingswidget.cpp index 3a13c1cdb..9b5dc7856 100644 --- a/widget/form/settingswidget.cpp +++ b/widget/form/settingswidget.cpp @@ -110,7 +110,7 @@ void SettingsWidget::prepButtons() // just straight up copying it like this... oh well // the layout/icons obviously need to be improved, but it's a working model, // not a pretty one - QSizePolicy sizePolicy3(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); + QSizePolicy sizePolicy3(QSizePolicy::Fixed, QSizePolicy::Fixed); sizePolicy3.setHorizontalStretch(0); sizePolicy3.setVerticalStretch(0); foot->setObjectName(QStringLiteral("foot")); From 9d36833a8ba0aea01bd0d615ff1e19cf2b62b81a Mon Sep 17 00:00:00 2001 From: dubslow Date: Mon, 15 Sep 2014 08:48:17 -0500 Subject: [PATCH 040/205] scaling still isn't quite right... --- widget/form/settings/avform.cpp | 2 +- widget/form/settings/generalform.cpp | 2 +- widget/form/settings/genericsettings.h | 4 ++-- widget/form/settings/identityform.cpp | 2 +- widget/form/settings/privacyform.cpp | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/widget/form/settings/avform.cpp b/widget/form/settings/avform.cpp index 5c0b38da3..e0b0773f9 100644 --- a/widget/form/settings/avform.cpp +++ b/widget/form/settings/avform.cpp @@ -19,7 +19,7 @@ AVForm::AVForm() { prep(); - icon.addFile(":/img/settings/av.png"); + icon.setPixmap(QPixmap(":/img/settings/av.png").scaledToHeight(headLayout.sizeHint().height(), Qt::SmoothTransformation)); label.setText(tr("Audio/Video settings")); } diff --git a/widget/form/settings/generalform.cpp b/widget/form/settings/generalform.cpp index a9810c1ae..7a6734383 100644 --- a/widget/form/settings/generalform.cpp +++ b/widget/form/settings/generalform.cpp @@ -20,7 +20,7 @@ GeneralForm::GeneralForm() { prep(); - icon.addFile(":/img/settings/general.png"); + icon.setPixmap(QPixmap(":/img/settings/general.png").scaledToHeight(headLayout.sizeHint().height(), Qt::SmoothTransformation)); label.setText(tr("General settings")); group = new QGroupBox(tr("General Settings")); enableIPv6 = new QCheckBox(); diff --git a/widget/form/settings/genericsettings.h b/widget/form/settings/genericsettings.h index 94f8fe90f..760d39cb0 100644 --- a/widget/form/settings/genericsettings.h +++ b/widget/form/settings/genericsettings.h @@ -19,6 +19,7 @@ #include #include +#include #include "widget/form/settingswidget.h" class GenericForm : public QObject @@ -36,8 +37,7 @@ public: protected: QVBoxLayout layout; QHBoxLayout headLayout; - QIcon icon; - QLabel label; + QLabel label, icon; QWidget head, body; void prep() // call in subclass constructor { diff --git a/widget/form/settings/identityform.cpp b/widget/form/settings/identityform.cpp index ac89257a9..696b2141a 100644 --- a/widget/form/settings/identityform.cpp +++ b/widget/form/settings/identityform.cpp @@ -22,7 +22,7 @@ IdentityForm::IdentityForm() { prep(); - icon.addFile(":/img/settings/identity.png"); + icon.setPixmap(QPixmap(":/img/settings/identity.png").scaledToHeight(headLayout.sizeHint().height(), Qt::SmoothTransformation)); label.setText(tr("Your identity")); toxGroup = new QGroupBox(tr("Tox ID")); QLabel* toxIdLabel = new QLabel(tr("Your Tox ID")); diff --git a/widget/form/settings/privacyform.cpp b/widget/form/settings/privacyform.cpp index ef7c54c4b..e1f737975 100644 --- a/widget/form/settings/privacyform.cpp +++ b/widget/form/settings/privacyform.cpp @@ -20,7 +20,7 @@ PrivacyForm::PrivacyForm() { prep(); - icon.addFile(":/img/settings/privacy.png"); + icon.setPixmap(QPixmap(":/img/settings/privacy.png").scaledToHeight(headLayout.sizeHint().height(), Qt::SmoothTransformation)); label.setText(tr("Privacy settings")); } From 35128e5048b2e05e0dca790d743c3249ee9e7e23 Mon Sep 17 00:00:00 2001 From: dubslow Date: Tue, 16 Sep 2014 12:13:21 -0500 Subject: [PATCH 041/205] cleanup --- widget/settingsdialog.cpp | 380 -------------------------------------- widget/settingsdialog.h | 64 ------- 2 files changed, 444 deletions(-) delete mode 100644 widget/settingsdialog.cpp delete mode 100644 widget/settingsdialog.h diff --git a/widget/settingsdialog.cpp b/widget/settingsdialog.cpp deleted file mode 100644 index d81973286..000000000 --- a/widget/settingsdialog.cpp +++ /dev/null @@ -1,380 +0,0 @@ -#include "settingsdialog.h" -#include "settings.h" -#include "widget.h" -#include "camera.h" -#include "selfcamview.h" -#include "core.h" -#include "smileypack.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -// ======================================= -// settings pages -//======================================== -class GeneralPage : public QWidget -{ - Q_OBJECT -public: - GeneralPage(QWidget *parent = 0) : - QWidget(parent) - { - QGroupBox *group = new QGroupBox(tr("General Settings"), this); - - enableIPv6 = new QCheckBox(this); - enableIPv6->setText(tr("Enable IPv6 (recommended)","Text on a checkbox to enable IPv6")); - useTranslations = new QCheckBox(this); - useTranslations->setText(tr("Use translations","Text on a checkbox to enable translations")); - makeToxPortable = new QCheckBox(this); - makeToxPortable->setText(tr("Make Tox portable","Text on a checkbox to make qTox a portable application")); - makeToxPortable->setToolTip(tr("Save settings to the working directory instead of the usual conf dir","describes makeToxPortable checkbox")); - - QVBoxLayout *vLayout = new QVBoxLayout(); - vLayout->addWidget(enableIPv6); - vLayout->addWidget(useTranslations); - vLayout->addWidget(makeToxPortable); - group->setLayout(vLayout); - - // theme - QGroupBox* themeGroup = new QGroupBox(tr("Theme")); - QLabel* smileyLabel = new QLabel(tr("Smiley Pack")); - smileyPack = new QComboBox(this); - - auto smileyPacks = SmileyPack::listSmileyPacks(); - for(auto pack : smileyPacks) - smileyPack->addItem(QString("%1 (%2)").arg(pack.first).arg(pack.second), pack.second); - - QVBoxLayout* themeLayout = new QVBoxLayout(); - themeLayout->addWidget(smileyLabel); - themeLayout->addWidget(smileyPack); - themeGroup->setLayout(themeLayout); - - QVBoxLayout *mainLayout = new QVBoxLayout(); - mainLayout->addWidget(group); - mainLayout->addWidget(themeGroup); - mainLayout->addStretch(1); - setLayout(mainLayout); - } - - QCheckBox* enableIPv6; - QCheckBox* useTranslations; - QCheckBox* makeToxPortable; - QComboBox* smileyPack; -}; - -class IdentityPage : public QWidget -{ - Q_OBJECT -public: - IdentityPage(QWidget* parent = 0) : - QWidget(parent) - { - // public - QGroupBox *publicGroup = new QGroupBox(tr("Public Information"), this); - QLabel* userNameLabel = new QLabel(tr("Name","Username/nick"), this); - userName = new QLineEdit(this); - QLabel* statusMessageLabel = new QLabel(tr("Status","Status message"), this); - statusMessage = new QLineEdit(this); - QVBoxLayout *vLayout = new QVBoxLayout(); - vLayout->addWidget(userNameLabel); - vLayout->addWidget(userName); - vLayout->addWidget(statusMessageLabel); - vLayout->addWidget(statusMessage); - publicGroup->setLayout(vLayout); - - // tox - QGroupBox* toxGroup = new QGroupBox(tr("Tox ID"), this); - QLabel* toxIdLabel = new QLabel(tr("Your Tox ID"), this); - toxID = new QLineEdit(this); - toxID->setReadOnly(true); - QVBoxLayout* toxLayout = new QVBoxLayout(); - toxLayout->addWidget(toxIdLabel); - toxLayout->addWidget(toxID); - toxGroup->setLayout(toxLayout); - - QVBoxLayout *mainLayout = new QVBoxLayout(); - mainLayout->setSpacing(30); - mainLayout->addWidget(publicGroup); - mainLayout->addWidget(toxGroup); - mainLayout->addStretch(1); - setLayout(mainLayout); - } - - QLineEdit* userName; - QLineEdit* statusMessage; - QLineEdit* toxID; -}; - -class PrivacyPage : public QWidget -{ -public: - PrivacyPage(QWidget* parent = 0) : - QWidget(parent) - {} -}; - -class AVPage : public QWidget -{ - Q_OBJECT -public: - AVPage(SettingsDialog* parent = 0) : - QWidget(parent) - { - QGroupBox *group = new QGroupBox(tr("Video Settings"), this); - - camView = new SelfCamView(parent->getWidget()->getCamera()); - camView->hide(); // hide by default - testVideo = new QPushButton(tr("Show video preview","On a button")); - connect(testVideo, SIGNAL(clicked()), this, SLOT(onTestVideoPressed())); - - QVBoxLayout *vLayout = new QVBoxLayout(); - vLayout->addWidget(testVideo); - vLayout->addWidget(camView); - group->setLayout(vLayout); - - QVBoxLayout *mainLayout = new QVBoxLayout(); - mainLayout->addWidget(group); - mainLayout->addStretch(1); - setLayout(mainLayout); - } - - ~AVPage() - { - delete camView; - } - - void showTestVideo() - { - testVideo->setText(tr("Hide video preview","On a button")); - camView->show(); - } - - void closeTestVideo() - { - testVideo->setText(tr("Show video preview","On a button")); - camView->close(); - } - - QPushButton* testVideo; - SelfCamView* camView; - -public slots: - void onTestVideoPressed() - { - if (camView->isVisible()) { - closeTestVideo(); - } else { - showTestVideo(); - } - } -}; - -// allows Q_OBJECT macro inside cpp -#include "settingsdialog.moc" - - - -// ======================================= -// settings dialog -//======================================== -SettingsDialog::SettingsDialog(Widget *parent) : - QDialog(parent), - widget(parent) -{ - createPages(); - createButtons(); - createConnections(); - createLayout(); - setWindowTitle(tr("qTox – Settings")); -} - -void SettingsDialog::createPages() -{ - generalPage = new GeneralPage(this); - identityPage = new IdentityPage(this); - privacyPage = new PrivacyPage(this); - avPage = new AVPage(this); - - contentsWidget = new QListWidget; - contentsWidget->setViewMode(QListView::IconMode); - contentsWidget->setIconSize(QSize(100, 73)); - contentsWidget->setMovement(QListView::Static); - contentsWidget->setMaximumWidth(110); - contentsWidget->setMinimumWidth(110); - contentsWidget->setSpacing(0); - contentsWidget->setFlow(QListView::TopToBottom); - - pagesWidget = new QStackedWidget; - pagesWidget->addWidget(generalPage); - pagesWidget->addWidget(identityPage); - pagesWidget->addWidget(privacyPage); - pagesWidget->addWidget(avPage); - - QListWidgetItem *generalButton = new QListWidgetItem(contentsWidget); - generalButton->setIcon(QIcon(":/img/settings/general.png")); - generalButton->setText(tr("General")); - generalButton->setTextAlignment(Qt::AlignHCenter); - generalButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); - - QListWidgetItem *identity = new QListWidgetItem(contentsWidget); - identity->setIcon(QIcon(":/img/settings/identity.png")); - identity->setText(tr("Identity")); - identity->setTextAlignment(Qt::AlignHCenter); - identity->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); - - QListWidgetItem *privacy = new QListWidgetItem(contentsWidget); - privacy->setIcon(QIcon(":/img/settings/privacy.png")); - privacy->setText(tr("Privacy")); - privacy->setTextAlignment(Qt::AlignHCenter); - privacy->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); - - QListWidgetItem *av = new QListWidgetItem(contentsWidget); - av->setIcon(QIcon(":/img/settings/av.png")); - av->setText(tr("Audio/Video")); - av->setTextAlignment(Qt::AlignHCenter); - av->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); - - contentsWidget->setCurrentRow(0); -} - -void SettingsDialog::createButtons() -{ - okButton = new QPushButton(tr("Ok"), this); - cancelButton = new QPushButton(tr("Cancel"), this); - applyButton = new QPushButton(tr("Apply"), this); -} - -void SettingsDialog::createConnections() -{ - connect(okButton, SIGNAL(clicked()), this, SLOT(okPressed())); - connect(cancelButton, SIGNAL(clicked()), this, SLOT(close())); - connect(applyButton, SIGNAL(clicked()), this, SLOT(applyPressed())); - connect( - contentsWidget, - SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), - this, - SLOT(changePage(QListWidgetItem*,QListWidgetItem*)) - ); -} - -void SettingsDialog::createLayout() -{ - setMinimumSize(800, 500); - - QHBoxLayout *buttonsLayout = new QHBoxLayout(); - buttonsLayout->addStretch(1); - buttonsLayout->addWidget(okButton); - buttonsLayout->addWidget(cancelButton); - buttonsLayout->addWidget(applyButton); - - QHBoxLayout *hLayout = new QHBoxLayout(); - hLayout->addWidget(contentsWidget); - hLayout->addWidget(pagesWidget, 1); - - QVBoxLayout *mainLayout = new QVBoxLayout(); - mainLayout->addLayout(hLayout); - mainLayout->addLayout(buttonsLayout); - setLayout(mainLayout); -} - -void SettingsDialog::changePage(QListWidgetItem *current, QListWidgetItem *previous) -{ - if (!current) { - current = previous; - } - pagesWidget->setCurrentIndex(contentsWidget->row(current)); -} - -void SettingsDialog::okPressed() -{ - writeConfig(); - close(); -} - -void SettingsDialog::cancelPressed() -{ - close(); -} - -void SettingsDialog::applyPressed() -{ - writeConfig(); -} - -void SettingsDialog::readConfig() -{ - Settings& settings = Settings::getInstance(); - Core* core = widget->getCore(); - - generalPage->enableIPv6->setChecked(settings.getEnableIPv6()); - generalPage->useTranslations->setChecked(settings.getUseTranslations()); - generalPage->makeToxPortable->setChecked(settings.getMakeToxPortable()); - - identityPage->userName->setText(core->getUsername()); - identityPage->statusMessage->setText(core->getStatusMessage()); - identityPage->toxID->setText(core->getSelfId().toString()); -} - -void SettingsDialog::writeConfig() -{ - Settings& settings = Settings::getInstance(); - Core* core = widget->getCore(); - - - // only save settings if something changed - bool saveSettings = false; - if (settings.getEnableIPv6() != generalPage->enableIPv6->isChecked()) { - settings.setEnableIPv6(generalPage->enableIPv6->isChecked()); - saveSettings = true; - } - - if (settings.getUseTranslations() != generalPage->useTranslations->isChecked()) { - settings.setUseTranslations(generalPage->useTranslations->isChecked()); - saveSettings = true; - } - - if (settings.getMakeToxPortable() != generalPage->makeToxPortable->isChecked()) { - settings.setMakeToxPortable(generalPage->makeToxPortable->isChecked()); - saveSettings = true; - } - - if (settings.getSmileyPack() != generalPage->smileyPack->currentData().toString()) { - settings.setSmileyPack(generalPage->smileyPack->currentData().toString()); - saveSettings = true; - } - - if (saveSettings) { - settings.save(); - } - - - // changing core settings will automatically save them - QString userName = identityPage->userName->text(); - if (core->getUsername() != userName) { - core->setUsername(userName); - } - - QString statusMessage = identityPage->statusMessage->text(); - if (core->getStatusMessage() != statusMessage) { - core->setStatusMessage(statusMessage); - } -} - -Widget* SettingsDialog::getWidget() -{ - return widget; -} - -void SettingsDialog::closeEvent(QCloseEvent* e){ - avPage->closeTestVideo(); - QDialog::closeEvent(e); -} diff --git a/widget/settingsdialog.h b/widget/settingsdialog.h deleted file mode 100644 index 55575b447..000000000 --- a/widget/settingsdialog.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef SETTINGSDIALOG_H -#define SETTINGSDIALOG_H - -#include -#include - -class Widget; -class SelfCamView; -class Camera; -class GeneralPage; -class IdentityPage; -class PrivacyPage; -class AVPage; - -class QListWidget; -class QListWidgetItem; -class QStackedWidget; -class QPushButton; -class QCheckBox; -class QLineEdit; - -// ======================================= -// settings dialog -//======================================== -class SettingsDialog : public QDialog -{ - Q_OBJECT -public: - explicit SettingsDialog(Widget *parent); - - void readConfig(); - void writeConfig(); - Widget* getWidget(); - void closeEvent(QCloseEvent *); - -public slots: - void changePage(QListWidgetItem *current, QListWidgetItem *previous); - void okPressed(); - void cancelPressed(); - void applyPressed(); - -private: - void createPages(); - void createButtons(); - void createConnections(); - void createLayout(); - - Widget* widget; - - // pages - GeneralPage* generalPage; - IdentityPage* identityPage; - PrivacyPage* privacyPage; - AVPage* avPage; - QListWidget* contentsWidget; - QStackedWidget* pagesWidget; - - // buttons - QPushButton* okButton; - QPushButton* cancelButton; - QPushButton* applyButton; -}; - -#endif // SETTINGSDIALOG_H From 9d3bcaa3877b9f94173f08d71d256ad185124a1b Mon Sep 17 00:00:00 2001 From: apprb Date: Thu, 18 Sep 2014 00:55:43 +0700 Subject: [PATCH 042/205] bug fix in ChatAreaWidget: absolute coordinates should be used to detect clicks on a FileTransferInstance's buttons --- widget/chatareawidget.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/widget/chatareawidget.cpp b/widget/chatareawidget.cpp index f06ec9534..f52262e5d 100644 --- a/widget/chatareawidget.cpp +++ b/widget/chatareawidget.cpp @@ -21,6 +21,7 @@ #include #include #include +#include ChatAreaWidget::ChatAreaWidget(QWidget *parent) : QTextBrowser(parent) @@ -64,12 +65,14 @@ ChatAreaWidget::~ChatAreaWidget() void ChatAreaWidget::mouseReleaseEvent(QMouseEvent * event) { QTextEdit::mouseReleaseEvent(event); - int pos = this->document()->documentLayout()->hitTest(event->pos(), Qt::ExactHit); + QPointF documentHitPost(event->pos().x() + horizontalScrollBar()->value(), event->pos().y() + verticalScrollBar()->value()); + int pos = this->document()->documentLayout()->hitTest(documentHitPost, Qt::ExactHit); if (pos > 0) { QTextCursor cursor(document()); - cursor.setPosition(pos); - if( ! cursor.atEnd() ) + cursor.setPosition(pos); + + if(!cursor.atEnd()) { cursor.setPosition(pos+1); @@ -85,6 +88,7 @@ void ChatAreaWidget::mouseReleaseEvent(QMouseEvent * event) int middlepos = data.indexOf("."); QString widgetID = data.left(middlepos); QString widgetBtn = data.right(data.length() - middlepos - 1); + qDebug() << "ChatAreaWidget::mouseReleaseEvent:" << widgetID << widgetBtn; emit onFileTranfertInterract(widgetID, widgetBtn); } } From d0c42533ac57ccd6331a185a1035a4333d888045 Mon Sep 17 00:00:00 2001 From: Zetok Zalbavar Date: Sat, 20 Sep 2014 20:56:06 +0100 Subject: [PATCH 043/205] Try fix jenkins windows builds --- qtox.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qtox.pro b/qtox.pro index 250d3abc8..9b7b4a3f8 100644 --- a/qtox.pro +++ b/qtox.pro @@ -46,7 +46,7 @@ contains(JENKINS,YES) { # Rules for Windows, Mac OSX, and Linux win32 { - LIBS += -L$$PWD/libs/lib -llibopencv_core249 -llibopencv_highgui249 -llibopencv_imgproc249 -lOpenAL32 + LIBS += -L$$PWD/libs/lib -lopencv_core249 -lopencv_highgui249 -lopencv_imgproc249 -lOpenAL32 LIBS += $$PWD/libs/lib/libtoxav.a $$PWD/libs/lib/libopus.a $$PWD/libs/lib/libvpx.a $$PWD/libs/lib/libtoxcore.a -lws2_32 $$PWD/libs/lib/libsodium.a -lpthread -liphlpapi } else { macx { From 68654179e99645198b24e78b00676ff0ada7dc63 Mon Sep 17 00:00:00 2001 From: apprb Date: Sun, 21 Sep 2014 17:30:10 +0700 Subject: [PATCH 044/205] Split message --- core.cpp | 46 +++++++++++++++++++++++++++++++++++++++++----- core.h | 3 +++ cstring.cpp | 19 ++++++++++++++++--- cstring.h | 3 +++ 4 files changed, 63 insertions(+), 8 deletions(-) diff --git a/core.cpp b/core.cpp index fe1e3187b..c37c78146 100644 --- a/core.cpp +++ b/core.cpp @@ -34,6 +34,7 @@ #include #include #include +#include const QString Core::CONFIG_FILE_NAME = "data"; QList Core::fileSendQueue; @@ -473,10 +474,13 @@ void Core::requestFriendship(const QString& friendAddress, const QString& messag void Core::sendMessage(int friendId, const QString& message) { - CString cMessage(message); + QList cMessages = splitMessage(message); - int messageId = tox_send_message(tox, friendId, cMessage.data(), cMessage.size()); - emit messageSentResult(friendId, message, messageId); + for (auto &cMsg :cMessages) + { + int messageId = tox_send_message(tox, friendId, cMsg.data(), cMsg.size()); + emit messageSentResult(friendId, message, messageId); + } } void Core::sendAction(int friendId, const QString &action) @@ -495,9 +499,12 @@ void Core::sendTyping(int friendId, bool typing) void Core::sendGroupMessage(int groupId, const QString& message) { - CString cMessage(message); + QList cMessages = splitMessage(message); - tox_group_message_send(tox, groupId, cMessage.data(), cMessage.size()); + for (auto &cMsg :cMessages) + { + tox_group_message_send(tox, groupId, cMsg.data(), cMsg.size()); + } } void Core::sendFile(int32_t friendId, QString Filename, QString FilePath, long long filesize) @@ -1159,3 +1166,32 @@ QString Core::getFriendAddress(int friendNumber) const return id; } + +QList Core::splitMessage(const QString &message) +{ + QList splittedMsgs; + QByteArray ba_message(message.toUtf8()); + + while (ba_message.size() > TOX_MAX_MESSAGE_LENGTH) + { + int splitPos = ba_message.lastIndexOf(' ', TOX_MAX_MESSAGE_LENGTH - 1); + if (splitPos <= 0) + { + splitPos = TOX_MAX_MESSAGE_LENGTH; + if (ba_message[splitPos] & 0x80) + { + do { + splitPos--; + } while (!(ba_message[splitPos] & 0x40)); + } + splitPos--; + } + + splittedMsgs.push_back(CString(ba_message.left(splitPos + 1))); + ba_message = ba_message.mid(splitPos + 1); + } + + splittedMsgs.push_back(CString(ba_message)); + + return splittedMsgs; +} diff --git a/core.h b/core.h index 13d051017..706f448a3 100644 --- a/core.h +++ b/core.h @@ -28,6 +28,7 @@ template class QList; class Camera; class QTimer; class QString; +class CString; class Core : public QObject { @@ -210,6 +211,8 @@ private: void checkLastOnline(int friendId); + QList splitMessage(const QString &message); + private slots: void onFileTransferFinished(ToxFile file); diff --git a/cstring.cpp b/cstring.cpp index 6d7815e9c..b9217fbc8 100644 --- a/cstring.cpp +++ b/cstring.cpp @@ -17,10 +17,23 @@ #include "cstring.h" #include -CString::CString(const QString& string) +CString::CString(const QString& string) : + CString(string.toUtf8()) { - cString = new uint8_t[string.length() * MAX_SIZE_OF_UTF8_ENCODED_CHARACTER](); - cStringSize = fromString(string, cString); +} + +CString::CString(const QByteArray& ba_string) +{ + cString = new uint8_t[ba_string.size()](); + cStringSize = ba_string.size(); + memcpy(cString, reinterpret_cast(ba_string.data()), cStringSize); +} + +CString::CString(const CString &cstr) +{ + cStringSize = cstr.cStringSize; + cString = new uint8_t[cStringSize](); + memcpy(cString, cstr.cString, cStringSize); } CString::~CString() diff --git a/cstring.h b/cstring.h index a75ed6468..818c79bc8 100644 --- a/cstring.h +++ b/cstring.h @@ -20,11 +20,14 @@ #include class QString; +class QByteArray; class CString { public: explicit CString(const QString& string); + explicit CString(const QByteArray& ba_string); + explicit CString(const CString& cstr); ~CString(); uint8_t* data(); From 5445746babc5a47f161d7c8e8edf084e584977e1 Mon Sep 17 00:00:00 2001 From: Joni Martikainen Date: Sun, 21 Sep 2014 23:28:04 +0300 Subject: [PATCH 045/205] Finnish translation to qTox Finnish translation to qTox --- qtox.pro | 1 + res.qrc | 1 + translations/fi.qm | Bin 0 -> 6809 bytes translations/fi.ts | 540 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 542 insertions(+) create mode 100644 translations/fi.qm create mode 100644 translations/fi.ts diff --git a/qtox.pro b/qtox.pro index 9b7b4a3f8..d22a406da 100644 --- a/qtox.pro +++ b/qtox.pro @@ -34,6 +34,7 @@ TRANSLATIONS = translations/de.ts \ translations/it.ts \ translations/ru.ts \ translations/pl.ts \ + translations/fi.ts \ translations/mannol.ts RESOURCES += res.qrc diff --git a/res.qrc b/res.qrc index f258db6f5..b1b50df58 100644 --- a/res.qrc +++ b/res.qrc @@ -140,6 +140,7 @@ img/settings/privacy.png img/settings/av.png translations/pl.qm + translations/fi.qm translations/mannol.qm diff --git a/translations/fi.qm b/translations/fi.qm new file mode 100644 index 0000000000000000000000000000000000000000..5d27bcc6d5c3b80822b48de838540dbc6051da8d GIT binary patch literal 6809 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 + + + + AVPage + + + Video Settings + Videoasetukset + + + + + Show video preview + On a button + Videon esikatselu + + + + Hide video preview + On a button + Lopeta esikatselu + + + + AddFriendForm + + + Add Friends + Lisää kontakti + + + + Tox ID + Tox ID of the person you're sending a friend request to + Tox ID + + + + Message + The message you send in friend requests + Viesti + + + + Send friend request + Lähetä kontaktipyyntö + + + + Tox me maybe? + Default message in friend requests if the field is left blank. Write something appropriate! + Lisää kontakteihin? + + + + Please fill in a valid Tox ID + Tox ID of the friend you're sending a friend request to + Anna kelvollinen Tox ID + + + + You can't add yourself as a friend! + When trying to add your own Tox ID as friend + Et voi lisätä itseäsi kontaktiksi + + + + This address does not exist + The DNS gives the Tox ID associated to toxme.se addresses + Osoitetta ei ole olemassa + + + + Error while looking up DNS + The DNS gives the Tox ID associated to toxme.se addresses + Virhe DNS pyynnössä + + + + Unexpected number of text records + Error with the DNS + Virheellinen määrä tekstitietueita + + + + Unexpected number of values in text record + Error with the DNS + Odottamaton määrä tekstitietueita + + + + The DNS lookup does not contain any Tox ID + Error with the DNS + DNS vastaus ei sisällä Tox ID:tä + + + + + The DNS lookup does not contain a valid Tox ID + Error with the DNS + DNS vastaus ei sisällä kelvollista Tox ID:tä + + + + Camera + + Camera eror + Kamerafehler + + + Camera format %1 not supported, can't use the camera + Kameraformat %1 wird nicht unterstützt. Die Kamera kann nicht verwendet werden + + + + ChatForm + + + Send a file + Lähetä tiedosto + + + Save chat log + Chatverlauf speichern + + + + CopyableElideLabel + + Copy + Kopieren + + + + FileTransferInstance + + + Save a file + Title of the file saving dialog + Tallenna tiedosto + + + + Location not writable + Title of permissions popup + Kohteeseen ei voi tallentaa + + + + You do not have permission to write that location. Choose another, or cancel the save dialog. + text of permissions popup + Käyttöoikeudet eivät riitä kohteeseen tallentamiseen. Valitse toinen kohde tai peru. + + + + FileTransfertWidget + + Save a file + Title of the file saving dialog + Datei speichern + + + + FilesForm + + + Transfered Files + "Headline" of the window + Tiedostojen siirrot + + + + Downloads + Ladatut + + + + Uploads + Lähetetyt + + + + FriendRequestDialog + + + Friend request + Title of the window to aceept/deny a friend request + Kontaktipyyntö + + + + Someone wants to make friends with you + Sinulle on lähetetty kontaktipyyntö + + + + User ID: + Käyttäjän ID: + + + + Friend request message: + Kontaktipyynnön viesti: + + + + Accept + Accept a friend request + Hyväksy + + + + Reject + Reject a friend request + Hylkää + + + + FriendWidget + + + Copy friend ID + Menu to copy the Tox ID of that friend + Kopioi kontaktin ID + + + + Invite in group + Menu to invite a friend in a groupchat + Kutsu ryhmään + + + + Remove friend + Menu to remove the friend from our friendlist + Poista kontakti + + + + GeneralPage + + + General Settings + Yleiset asetukset + + + + Enable IPv6 (recommended) + Text on a checkbox to enable IPv6 + Aktivoi IPv6 (suositeltu) + + + + Use translations + Text on a checkbox to enable translations + Käytä käännöksiä + + + + Make Tox portable + Text on a checkbox to make qTox a portable application + Tee ohjelmasta siirrettävä + + + + Save settings to the working directory instead of the usual conf dir + describes makeToxPortable checkbox + Tallenna asetukset työhakemistoon normaalin asetushakemiston sijaan. + + + + Theme + Teema + + + + Smiley Pack + Hymiö-paketti + + + + GenericChatForm + + + + Save chat log + Tallenna keskustelu + + + + GroupChatForm + + + %1 users in chat + Number of users in chat + %1 henkilö keskustelussa + + + + <Unknown> + <Tuntematon> + + + + %1 users in chat + %1 henkilöä keskustelussa + + + Save chat log + Chatverlauf speichern + + + + GroupWidget + + + + %1 users in chat + %1 henkilöä keskustelussa + + + + + 0 users in chat + 0 henkilöä keskustelussa + + + + Quit group + Menu to quit a groupchat + Sulje ryhmä + + + + IdentityPage + + + Public Information + Julkiset tiedot + + + + Name + Username/nick + Nimi + + + + Status + Status message + Tila + + + + Tox ID + Tox ID + + + + Your Tox ID + Sinun Tox ID + + + + MainWindow + + + qTox + + + + + Your name + Sinun nimesi + + + + Your status + Sinun tilasi + + + + Add friends + Lisää kontakti + + + + Create a group chat + Luo keskusteluryhmä + + + + View completed file transfers + Näytä valmiit tiedostojensiirrot + + + + Change your settings + Muuta asetuksiasi + + + + Close + Sulje + + + + Ctrl+Q + Ctrl+Q + + + + SelfCamView + + + Tox video test + Title of the window to test the video/webcam + Tox videotesti + + + + SettingsDialog + + + qTox – Settings + qTox - Asetukset + + + + General + Yleiset + + + + Identity + Identiteetti + + + + Privacy + Yksityisyys + + + + Audio/Video + Audio/Video + + + + Ok + Ok + + + + Cancel + Peru + + + + Apply + Ota käyttöön + + + + SettingsForm + + User Settings + "Headline" of the window + Einstellungen + + + Name + Username/nick + Benutzername + + + Status + Status message + Status + + + Test video + Text on a button to test the video/webcam + Video testen + + + Enable IPv6 (recommended) + Text on a checkbox to enable IPv6 + IPv6 aktivieren (empfohlen) + + + + Widget + + Tox + Tox + + + Your name + Dein Name + + + Your status + Dein Status + + + Close + Schließen + + + Ctrl+Q + Strg+Q + + + + Online + Button to set your status to 'Online' + Online + + + + Away + Button to set your status to 'Away' + Poissa + + + + Busy + Button to set your status to 'Busy' + Kiireinen + + + + <Unknown> + Placeholder when we don't know someone's name in a group chat + <tuntematon> + + + From 4c18f6184e42401169d05c9c80599c338c547a4b Mon Sep 17 00:00:00 2001 From: Urras Date: Mon, 22 Sep 2014 09:31:44 -0400 Subject: [PATCH 046/205] Update Screenshot --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index dd7c45fdb..6f13e095a 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ This client runs on Windows, Linux and Mac natively.

Screenshots

Note: The screenshots may not always be up to date, but they should give a good idea of the general look and features
-/ + ##Documentation: From 15516140704469c09ec5e6f17671ec99f8b7eef4 Mon Sep 17 00:00:00 2001 From: apprb Date: Tue, 23 Sep 2014 23:35:06 +0700 Subject: [PATCH 047/205] Error messages in the case of message sending problems --- core.cpp | 7 +- core.h | 1 + qtox.pro | 14 +- widget/chatareawidget.cpp | 2 +- widget/form/chatform.cpp | 2 +- widget/form/genericchatform.cpp | 11 +- widget/form/genericchatform.h | 1 + widget/tool/chataction.cpp | 169 ------------------ widget/tool/chatactions/chataction.cpp | 53 ++++++ widget/tool/{ => chatactions}/chataction.h | 29 --- .../tool/chatactions/filetransferaction.cpp | 75 ++++++++ widget/tool/chatactions/filetransferaction.h | 39 ++++ widget/tool/chatactions/messageaction.cpp | 75 ++++++++ widget/tool/chatactions/messageaction.h | 34 ++++ .../tool/chatactions/systemmessageaction.cpp | 46 +++++ widget/tool/chatactions/systemmessageaction.h | 37 ++++ widget/widget.cpp | 25 +++ widget/widget.h | 2 + 18 files changed, 415 insertions(+), 207 deletions(-) delete mode 100644 widget/tool/chataction.cpp create mode 100644 widget/tool/chatactions/chataction.cpp rename widget/tool/{ => chatactions}/chataction.h (64%) create mode 100644 widget/tool/chatactions/filetransferaction.cpp create mode 100644 widget/tool/chatactions/filetransferaction.h create mode 100644 widget/tool/chatactions/messageaction.cpp create mode 100644 widget/tool/chatactions/messageaction.h create mode 100644 widget/tool/chatactions/systemmessageaction.cpp create mode 100644 widget/tool/chatactions/systemmessageaction.h diff --git a/core.cpp b/core.cpp index c37c78146..e44988d56 100644 --- a/core.cpp +++ b/core.cpp @@ -479,7 +479,8 @@ void Core::sendMessage(int friendId, const QString& message) for (auto &cMsg :cMessages) { int messageId = tox_send_message(tox, friendId, cMsg.data(), cMsg.size()); - emit messageSentResult(friendId, message, messageId); + if (messageId == 0) + emit messageSentResult(friendId, message, messageId); } } @@ -503,7 +504,9 @@ void Core::sendGroupMessage(int groupId, const QString& message) for (auto &cMsg :cMessages) { - tox_group_message_send(tox, groupId, cMsg.data(), cMsg.size()); + int ret = tox_group_message_send(tox, groupId, cMsg.data(), cMsg.size()); + if (ret == -1) + emit groupSentResult(groupId, message, ret); } } diff --git a/core.h b/core.h index 706f448a3..ed1606331 100644 --- a/core.h +++ b/core.h @@ -125,6 +125,7 @@ signals: void statusSet(Status status); void messageSentResult(int friendId, const QString& message, int messageId); + void groupSentResult(int groupId, const QString& message, int result); void actionSentResult(int friendId, const QString& action, int success); void failedToAddFriend(const QString& userId); diff --git a/qtox.pro b/qtox.pro index d22a406da..68845488e 100644 --- a/qtox.pro +++ b/qtox.pro @@ -107,13 +107,16 @@ HEADERS += widget/form/addfriendform.h \ widget/friendlistwidget.h \ widget/genericchatroomwidget.h \ widget/form/genericchatform.h \ - widget/tool/chataction.h \ + widget/tool/chatactions/chataction.h \ widget/chatareawidget.h \ filetransferinstance.h \ corestructs.h \ coredefines.h \ coreav.h \ - widget/settingsdialog.h + widget/settingsdialog.h \ + widget/tool/chatactions/messageaction.h \ + widget/tool/chatactions/filetransferaction.h \ + widget/tool/chatactions/systemmessageaction.h SOURCES += \ widget/form/addfriendform.cpp \ @@ -146,8 +149,11 @@ SOURCES += \ coreav.cpp \ widget/genericchatroomwidget.cpp \ widget/form/genericchatform.cpp \ - widget/tool/chataction.cpp \ + widget/tool/chatactions/chataction.cpp \ widget/chatareawidget.cpp \ filetransferinstance.cpp \ corestructs.cpp \ - widget/settingsdialog.cpp + widget/settingsdialog.cpp \ + widget/tool/chatactions/messageaction.cpp \ + widget/tool/chatactions/filetransferaction.cpp \ + widget/tool/chatactions/systemmessageaction.cpp diff --git a/widget/chatareawidget.cpp b/widget/chatareawidget.cpp index f52262e5d..524039d20 100644 --- a/widget/chatareawidget.cpp +++ b/widget/chatareawidget.cpp @@ -15,7 +15,7 @@ */ #include "chatareawidget.h" -#include "widget/tool/chataction.h" +#include "widget/tool/chatactions/chataction.h" #include #include #include diff --git a/widget/form/chatform.cpp b/widget/form/chatform.cpp index 0114a92db..33e32879a 100644 --- a/widget/form/chatform.cpp +++ b/widget/form/chatform.cpp @@ -23,7 +23,7 @@ #include "friend.h" #include "widget/friendwidget.h" #include "filetransferinstance.h" -#include "widget/tool/chataction.h" +#include "widget/tool/chatactions/filetransferaction.h" #include "widget/netcamview.h" #include "widget/chatareawidget.h" #include "widget/tool/chattextedit.h" diff --git a/widget/form/genericchatform.cpp b/widget/form/genericchatform.cpp index f5681f1c6..0e765b397 100644 --- a/widget/form/genericchatform.cpp +++ b/widget/form/genericchatform.cpp @@ -22,7 +22,8 @@ #include "style.h" #include "widget/widget.h" #include "settings.h" -#include "widget/tool/chataction.h" +#include "widget/tool/chatactions/messageaction.h" +#include "widget/tool/chatactions/systemmessageaction.h" #include "widget/chatareawidget.h" #include "widget/tool/chattextedit.h" @@ -208,3 +209,11 @@ void GenericChatForm::focusInput() { msgEdit->setFocus(); } + +void GenericChatForm::addSystemInfoMessage(const QString &message, const QString &type, const QDateTime &datetime) +{ + previousName = ""; + QString date = datetime.toString(Settings::getInstance().getTimestampFormat()); + + chatWidget->insertMessage(new SystemMessageAction(message, type, date)); +} diff --git a/widget/form/genericchatform.h b/widget/form/genericchatform.h index 95940cda5..72dc94fd9 100644 --- a/widget/form/genericchatform.h +++ b/widget/form/genericchatform.h @@ -45,6 +45,7 @@ public: virtual void setName(const QString &newName); virtual void show(Ui::MainWindow &ui); void addMessage(QString author, QString message, QDateTime datetime=QDateTime::currentDateTime()); + void addSystemInfoMessage(const QString &message, const QString &type, const QDateTime &datetime=QDateTime::currentDateTime()); signals: void sendMessage(int, QString); diff --git a/widget/tool/chataction.cpp b/widget/tool/chataction.cpp deleted file mode 100644 index bcd1f1080..000000000 --- a/widget/tool/chataction.cpp +++ /dev/null @@ -1,169 +0,0 @@ -/* - Copyright (C) 2014 by Project Tox - - This file is part of qTox, a Qt-based graphical interface for Tox. - - This program 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. - 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 COPYING file for more details. -*/ - -#include "chataction.h" -#include "smileypack.h" -#include -#include -#include "filetransferinstance.h" - -QString ChatAction::toHtmlChars(const QString &str) -{ - static QList> replaceList = {{"&","&"}, {">",">"}, {"<","<"}}; - QString res = str; - - for (auto &it : replaceList) - res = res.replace(it.first,it.second); - - return res; -} - -QString ChatAction::QImage2base64(const QImage &img) -{ - QByteArray ba; - QBuffer buffer(&ba); - buffer.open(QIODevice::WriteOnly); - img.save(&buffer, "PNG"); // writes image into ba in PNG format - return ba.toBase64(); -} - -QString ChatAction::getName() -{ - if (isMe) - return QString("
" + toHtmlChars(name) + "
"); - else - return QString("
" + toHtmlChars(name) + "
"); -} - -QString ChatAction::getDate() -{ - QString res = date; - return res; -} - -MessageAction::MessageAction(const QString &author, const QString &message, const QString &date, const bool &me) : - ChatAction(me, author, date), - message(message) -{ -} - -void MessageAction::setTextCursor(QTextCursor cursor) -{ - // When this function is called, we're supposed to only update ourselve when needed - // Nobody should ask us to do anything with our content, we're on our own - // Except we never udpate on our own, so we can safely free our resources - - (void) cursor; - message.clear(); - message.squeeze(); - name.clear(); - name.squeeze(); - date.clear(); - date.squeeze(); -} - -QString MessageAction::getMessage() -{ - QString message_ = SmileyPack::getInstance().smileyfied(toHtmlChars(message)); - - // detect urls - QRegExp exp("(www\\.|http[s]?:\\/\\/|ftp:\\/\\/)\\S+"); - int offset = 0; - while ((offset = exp.indexIn(message_, offset)) != -1) - { - QString url = exp.cap(); - - // add scheme if not specified - if (exp.cap(1) == "www.") - url.prepend("http://"); - - QString htmledUrl = QString("%1").arg(url); - message_.replace(offset, exp.cap().length(), htmledUrl); - - offset += htmledUrl.length(); - } - - // detect text quotes - QStringList messageLines = message_.split("\n"); - message_ = ""; - for (QString& s : messageLines) - { - if (QRegExp("^[ ]*>.*").exactMatch(s)) - message_ += ">" + s.right(s.length()-4) + "
"; - else - message_ += s + "
"; - } - message_ = message_.left(message_.length()-4); - - return QString("
" + message_ + "
"); -} - -FileTransferAction::FileTransferAction(FileTransferInstance *widget, const QString &author, const QString &date, const bool &me) : - ChatAction(me, author, date) -{ - w = widget; - - connect(w, &FileTransferInstance::stateUpdated, this, &FileTransferAction::updateHtml); -} - -FileTransferAction::~FileTransferAction() -{ -} - -QString FileTransferAction::getMessage() -{ - QString widgetHtml; - if (w != nullptr) - widgetHtml = w->getHtmlImage(); - else - widgetHtml = "
EMPTY CONTENT
"; - return widgetHtml; -} - -void FileTransferAction::setTextCursor(QTextCursor cursor) -{ - cur = cursor; - cur.setKeepPositionOnInsert(true); - int end=cur.selectionEnd(); - cur.setPosition(cur.position()); - cur.setPosition(end, QTextCursor::KeepAnchor); -} - -void FileTransferAction::updateHtml() -{ - if (cur.isNull()) - return; - - int pos = cur.selectionStart(); - cur.removeSelectedText(); - cur.setKeepPositionOnInsert(false); - cur.insertHtml(getMessage()); - cur.setKeepPositionOnInsert(true); - int end = cur.position(); - cur.setPosition(pos); - cur.setPosition(end, QTextCursor::KeepAnchor); - - // Free our ressources if we'll never need to update again - if (w->getState() == FileTransferInstance::TransfState::tsCanceled - || w->getState() == FileTransferInstance::TransfState::tsFinished) - { - name.clear(); - name.squeeze(); - date.clear(); - date.squeeze(); - cur = QTextCursor(); - } -} diff --git a/widget/tool/chatactions/chataction.cpp b/widget/tool/chatactions/chataction.cpp new file mode 100644 index 000000000..7758aae33 --- /dev/null +++ b/widget/tool/chatactions/chataction.cpp @@ -0,0 +1,53 @@ +/* + Copyright (C) 2014 by Project Tox + + This file is part of qTox, a Qt-based graphical interface for Tox. + + This program 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. + 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 COPYING file for more details. +*/ + +#include "chataction.h" +#include +#include + +QString ChatAction::toHtmlChars(const QString &str) +{ + static QList> replaceList = {{"&","&"}, {">",">"}, {"<","<"}}; + QString res = str; + + for (auto &it : replaceList) + res = res.replace(it.first,it.second); + + return res; +} + +QString ChatAction::QImage2base64(const QImage &img) +{ + QByteArray ba; + QBuffer buffer(&ba); + buffer.open(QIODevice::WriteOnly); + img.save(&buffer, "PNG"); // writes image into ba in PNG format + return ba.toBase64(); +} + +QString ChatAction::getName() +{ + if (isMe) + return QString("
" + toHtmlChars(name) + "
"); + else + return QString("
" + toHtmlChars(name) + "
"); +} + +QString ChatAction::getDate() +{ + QString res = date; + return res; +} diff --git a/widget/tool/chataction.h b/widget/tool/chatactions/chataction.h similarity index 64% rename from widget/tool/chataction.h rename to widget/tool/chatactions/chataction.h index a324a41c6..16c9f179b 100644 --- a/widget/tool/chataction.h +++ b/widget/tool/chatactions/chataction.h @@ -42,33 +42,4 @@ protected: QString name, date; }; -class MessageAction : public ChatAction -{ -public: - MessageAction(const QString &author, const QString &message, const QString &date, const bool &me); - virtual ~MessageAction(){;} - virtual QString getMessage(); - virtual void setTextCursor(QTextCursor cursor) final; - -private: - QString message; -}; - -class FileTransferAction : public ChatAction -{ - Q_OBJECT -public: - FileTransferAction(FileTransferInstance *widget, const QString &author, const QString &date, const bool &me); - virtual ~FileTransferAction(); - virtual QString getMessage(); - virtual void setTextCursor(QTextCursor cursor) final; - -private slots: - void updateHtml(); - -private: - FileTransferInstance *w; - QTextCursor cur; -}; - #endif // CHATACTION_H diff --git a/widget/tool/chatactions/filetransferaction.cpp b/widget/tool/chatactions/filetransferaction.cpp new file mode 100644 index 000000000..12e2a1ac6 --- /dev/null +++ b/widget/tool/chatactions/filetransferaction.cpp @@ -0,0 +1,75 @@ +/* + Copyright (C) 2014 by Project Tox + + This file is part of qTox, a Qt-based graphical interface for Tox. + + This program 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. + 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 COPYING file for more details. +*/ + +#include "filetransferaction.h" +#include "filetransferinstance.h" + +FileTransferAction::FileTransferAction(FileTransferInstance *widget, const QString &author, const QString &date, const bool &me) : + ChatAction(me, author, date) +{ + w = widget; + + connect(w, &FileTransferInstance::stateUpdated, this, &FileTransferAction::updateHtml); +} + +FileTransferAction::~FileTransferAction() +{ +} + +QString FileTransferAction::getMessage() +{ + QString widgetHtml; + if (w != nullptr) + widgetHtml = w->getHtmlImage(); + else + widgetHtml = "
EMPTY CONTENT
"; + return widgetHtml; +} + +void FileTransferAction::setTextCursor(QTextCursor cursor) +{ + cur = cursor; + cur.setKeepPositionOnInsert(true); + int end=cur.selectionEnd(); + cur.setPosition(cur.position()); + cur.setPosition(end, QTextCursor::KeepAnchor); +} + +void FileTransferAction::updateHtml() +{ + if (cur.isNull()) + return; + + int pos = cur.selectionStart(); + cur.removeSelectedText(); + cur.setKeepPositionOnInsert(false); + cur.insertHtml(getMessage()); + cur.setKeepPositionOnInsert(true); + int end = cur.position(); + cur.setPosition(pos); + cur.setPosition(end, QTextCursor::KeepAnchor); + + // Free our ressources if we'll never need to update again + if (w->getState() == FileTransferInstance::TransfState::tsCanceled + || w->getState() == FileTransferInstance::TransfState::tsFinished) + { + name.clear(); + name.squeeze(); + date.clear(); + date.squeeze(); + cur = QTextCursor(); + } +} diff --git a/widget/tool/chatactions/filetransferaction.h b/widget/tool/chatactions/filetransferaction.h new file mode 100644 index 000000000..ee6d0e11c --- /dev/null +++ b/widget/tool/chatactions/filetransferaction.h @@ -0,0 +1,39 @@ +/* + Copyright (C) 2014 by Project Tox + + This file is part of qTox, a Qt-based graphical interface for Tox. + + This program 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. + 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 COPYING file for more details. +*/ + +#ifndef FILETRANSFERACTION_H +#define FILETRANSFERACTION_H + +#include "widget/tool/chatactions/chataction.h" + +class FileTransferAction : public ChatAction +{ + Q_OBJECT +public: + FileTransferAction(FileTransferInstance *widget, const QString &author, const QString &date, const bool &me); + virtual ~FileTransferAction(); + virtual QString getMessage(); + virtual void setTextCursor(QTextCursor cursor) final; + +private slots: + void updateHtml(); + +private: + FileTransferInstance *w; + QTextCursor cur; +}; + +#endif // FILETRANSFERACTION_H diff --git a/widget/tool/chatactions/messageaction.cpp b/widget/tool/chatactions/messageaction.cpp new file mode 100644 index 000000000..fa396468c --- /dev/null +++ b/widget/tool/chatactions/messageaction.cpp @@ -0,0 +1,75 @@ +/* + Copyright (C) 2014 by Project Tox + + This file is part of qTox, a Qt-based graphical interface for Tox. + + This program 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. + 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 COPYING file for more details. +*/ + +#include "messageaction.h" +#include "smileypack.h" + +MessageAction::MessageAction(const QString &author, const QString &message, const QString &date, const bool &me) : + ChatAction(me, author, date), + message(message) +{ +} + +void MessageAction::setTextCursor(QTextCursor cursor) +{ + // When this function is called, we're supposed to only update ourselve when needed + // Nobody should ask us to do anything with our content, we're on our own + // Except we never udpate on our own, so we can safely free our resources + + (void) cursor; + message.clear(); + message.squeeze(); + name.clear(); + name.squeeze(); + date.clear(); + date.squeeze(); +} + +QString MessageAction::getMessage() +{ + QString message_ = SmileyPack::getInstance().smileyfied(toHtmlChars(message)); + + // detect urls + QRegExp exp("(www\\.|http[s]?:\\/\\/|ftp:\\/\\/)\\S+"); + int offset = 0; + while ((offset = exp.indexIn(message_, offset)) != -1) + { + QString url = exp.cap(); + + // add scheme if not specified + if (exp.cap(1) == "www.") + url.prepend("http://"); + + QString htmledUrl = QString("%1").arg(url); + message_.replace(offset, exp.cap().length(), htmledUrl); + + offset += htmledUrl.length(); + } + + // detect text quotes + QStringList messageLines = message_.split("\n"); + message_ = ""; + for (QString& s : messageLines) + { + if (QRegExp("^[ ]*>.*").exactMatch(s)) + message_ += ">" + s.right(s.length()-4) + "
"; + else + message_ += s + "
"; + } + message_ = message_.left(message_.length()-4); + + return QString("
" + message_ + "
"); +} diff --git a/widget/tool/chatactions/messageaction.h b/widget/tool/chatactions/messageaction.h new file mode 100644 index 000000000..baa68898a --- /dev/null +++ b/widget/tool/chatactions/messageaction.h @@ -0,0 +1,34 @@ +/* + Copyright (C) 2014 by Project Tox + + This file is part of qTox, a Qt-based graphical interface for Tox. + + This program 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. + 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 COPYING file for more details. +*/ + +#ifndef MESSAGEACTION_H +#define MESSAGEACTION_H + +#include "widget/tool/chatactions/chataction.h" + +class MessageAction : public ChatAction +{ +public: + MessageAction(const QString &author, const QString &message, const QString &date, const bool &me); + virtual ~MessageAction(){;} + virtual QString getMessage(); + virtual void setTextCursor(QTextCursor cursor) final; + +private: + QString message; +}; + +#endif // MESSAGEACTION_H diff --git a/widget/tool/chatactions/systemmessageaction.cpp b/widget/tool/chatactions/systemmessageaction.cpp new file mode 100644 index 000000000..32457c6ed --- /dev/null +++ b/widget/tool/chatactions/systemmessageaction.cpp @@ -0,0 +1,46 @@ +/* + Copyright (C) 2014 by Project Tox + + This file is part of qTox, a Qt-based graphical interface for Tox. + + This program 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. + 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 COPYING file for more details. +*/ + +#include "systemmessageaction.h" + +SystemMessageAction::SystemMessageAction(const QString &message, const QString &type, const QString &date) : + ChatAction(false, QString(), date), + message(message), + type(type) +{ +} + +QString SystemMessageAction::getMessage() +{ + return QString("
" + message + "
"); +} + +void SystemMessageAction::setTextCursor(QTextCursor cursor) +{ + // When this function is called, we're supposed to only update ourselve when needed + // Nobody should ask us to do anything with our content, we're on our own + // Except we never udpate on our own, so we can safely free our resources + + (void) cursor; + message.clear(); + message.squeeze(); + name.clear(); + name.squeeze(); + date.clear(); + date.squeeze(); + type.clear(); + type.squeeze(); +} diff --git a/widget/tool/chatactions/systemmessageaction.h b/widget/tool/chatactions/systemmessageaction.h new file mode 100644 index 000000000..b628f7e04 --- /dev/null +++ b/widget/tool/chatactions/systemmessageaction.h @@ -0,0 +1,37 @@ +/* + Copyright (C) 2014 by Project Tox + + This file is part of qTox, a Qt-based graphical interface for Tox. + + This program 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. + 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 COPYING file for more details. +*/ + +#ifndef SYSTEMMESSAGEACTION_H +#define SYSTEMMESSAGEACTION_H + +#include "widget/tool/chatactions/chataction.h" + +class SystemMessageAction : public ChatAction +{ +public: + SystemMessageAction(const QString &message, const QString& type, const QString &date); + virtual ~SystemMessageAction(){;} + virtual void setTextCursor(QTextCursor cursor) final; + + virtual QString getName() {return QString();} + virtual QString getMessage(); + +private: + QString message; + QString type; +}; + +#endif // SYSTEMMESSAGEACTION_H diff --git a/widget/widget.cpp b/widget/widget.cpp index 36b2c33c1..64b09de80 100644 --- a/widget/widget.cpp +++ b/widget/widget.cpp @@ -197,6 +197,9 @@ Widget::Widget(QWidget *parent) connect(core, &Core::groupNamelistChanged, this, &Widget::onGroupNamelistChanged); connect(core, &Core::emptyGroupCreated, this, &Widget::onEmptyGroupCreated); + connect(core, SIGNAL(messageSentResult(int,QString,int)), this, SLOT(onMessageSendResult(int,QString,int))); + connect(core, SIGNAL(groupSentResult(int,QString,int)), this, SLOT(onGroupSendResult(int,QString,int))); + connect(this, &Widget::statusSet, core, &Core::setStatus); connect(this, &Widget::friendRequested, core, &Core::requestFriendship); connect(this, &Widget::friendRequestAccepted, core, &Core::acceptFriendRequest); @@ -1060,3 +1063,25 @@ bool Widget::getIsWindowMinimized() { return static_cast(isWindowMinimized); } + +void Widget::onMessageSendResult(int friendId, const QString& message, int messageId) +{ + Q_UNUSED(message) + Friend* f = FriendList::findFriend(friendId); + if (!f) + return; + + if (!messageId) + f->chatForm->addSystemInfoMessage("Message failed to send", "red"); +} + +void Widget::onGroupSendResult(int groupId, const QString& message, int result) +{ + Q_UNUSED(message) + Group* g = GroupList::findGroup(groupId); + if (!g) + return; + + if (result == -1) + g->chatForm->addSystemInfoMessage("Message failed to send", "red"); +} diff --git a/widget/widget.h b/widget/widget.h index 035ea2ae0..e85701a55 100644 --- a/widget/widget.h +++ b/widget/widget.h @@ -104,6 +104,8 @@ private slots: void setStatusOnline(); void setStatusAway(); void setStatusBusy(); + void onMessageSendResult(int friendId, const QString& message, int messageId); + void onGroupSendResult(int groupId, const QString& message, int result); protected slots: void moveWindow(QMouseEvent *e); From 06178f00d99398213094b70290a626a5b8aa4f28 Mon Sep 17 00:00:00 2001 From: apprb Date: Tue, 23 Sep 2014 23:52:06 +0700 Subject: [PATCH 048/205] File send error message --- core.cpp | 1 + core.h | 2 ++ widget/form/chatform.cpp | 9 +++++++++ widget/form/chatform.h | 1 + 4 files changed, 13 insertions(+) diff --git a/core.cpp b/core.cpp index e44988d56..a9b0843c3 100644 --- a/core.cpp +++ b/core.cpp @@ -517,6 +517,7 @@ void Core::sendFile(int32_t friendId, QString Filename, QString FilePath, long l if (fileNum == -1) { qWarning() << "Core::sendFile: Can't create the Tox file sender"; + emit fileSendFailed(friendId, Filename); return; } qDebug() << QString("Core::sendFile: Created file sender %1 with friend %2").arg(fileNum).arg(friendId); diff --git a/core.h b/core.h index ed1606331..0ae48f688 100644 --- a/core.h +++ b/core.h @@ -150,6 +150,8 @@ signals: void fileTransferInfo(int FriendId, int FileNum, int64_t Filesize, int64_t BytesSent, ToxFile::FileDirection direction); void fileTransferRemotePausedUnpaused(ToxFile file, bool paused); + void fileSendFailed(int FriendId, const QString& fname); + void avInvite(int friendId, int callIndex, bool video); void avStart(int friendId, int callIndex, bool video); void avCancel(int friendId, int callIndex); diff --git a/widget/form/chatform.cpp b/widget/form/chatform.cpp index 33e32879a..f8b950b7b 100644 --- a/widget/form/chatform.cpp +++ b/widget/form/chatform.cpp @@ -51,6 +51,7 @@ ChatForm::ChatForm(Friend* chatFriend) connect(msgEdit, &ChatTextEdit::enterPressed, this, &ChatForm::onSendTriggered); connect(micButton, SIGNAL(clicked()), this, SLOT(onMicMuteToggle())); connect(chatWidget, &ChatAreaWidget::onFileTranfertInterract, this, &ChatForm::onFileTansBtnClicked); + connect(Core::getInstance(), &Core::fileSendFailed, this, &ChatForm::onFileSendFailed); } ChatForm::~ChatForm() @@ -455,3 +456,11 @@ void ChatForm::onFileTansBtnClicked(QString widgetName, QString buttonName) else qDebug() << "no filetransferwidget: " << id; } + +void ChatForm::onFileSendFailed(int FriendId, const QString &fname) +{ + if (FriendId != f->friendId) + return; + + addSystemInfoMessage("File: \"" + fname + "\" failed to send.", "red"); +} diff --git a/widget/form/chatform.h b/widget/form/chatform.h index 93bc2d6b4..43681562c 100644 --- a/widget/form/chatform.h +++ b/widget/form/chatform.h @@ -65,6 +65,7 @@ private slots: void onHangupCallTriggered(); void onCancelCallTriggered(); void onFileTansBtnClicked(QString widgetName, QString buttonName); + void onFileSendFailed(int FriendId, const QString &fname); private: Friend* f; From 7ad6ad2731680632c7d21af330c0e62ce56b8d4c Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Wed, 24 Sep 2014 16:51:16 +0200 Subject: [PATCH 049/205] Avatar support for ourselves --- core.cpp | 46 +++++++++++++++++++++++++++++++- core.h | 4 +++ mainwindow.ui | 11 +++++--- qtox.pro | 3 ++- settings.cpp | 15 +++++++++++ settings.h | 5 ++++ widget/tool/clickablelabel.h | 22 ++++++++++++++++ widget/widget.cpp | 51 ++++++++++++++++++++++++++++++++++++ widget/widget.h | 2 ++ 9 files changed, 154 insertions(+), 5 deletions(-) create mode 100644 widget/tool/clickablelabel.h diff --git a/core.cpp b/core.cpp index a9b0843c3..d63461c07 100644 --- a/core.cpp +++ b/core.cpp @@ -35,6 +35,7 @@ #include #include #include +#include const QString Core::CONFIG_FILE_NAME = "data"; QList Core::fileSendQueue; @@ -187,6 +188,8 @@ void Core::start() tox_callback_file_send_request(tox, onFileSendRequestCallback, this); tox_callback_file_control(tox, onFileControlCallback, this); tox_callback_file_data(tox, onFileDataCallback, this); + tox_callback_avatar_info(tox, onAvatarInfoCallback, this); + tox_callback_avatar_data(tox, onAvatarDataCallback, this); toxav_register_callstate_callback(toxav, onAvInvite, av_OnInvite, this); toxav_register_callstate_callback(toxav, onAvStart, av_OnStart, this); @@ -205,9 +208,22 @@ void Core::start() uint8_t friendAddress[TOX_FRIEND_ADDRESS_SIZE]; tox_get_address(tox, friendAddress); - emit friendAddressGenerated(CFriendAddress::toString(friendAddress)); + QPixmap pic = Settings::getInstance().getSavedAvatar(); + if (!pic.isNull() && !pic.size().isEmpty()) + { + QByteArray data; + QBuffer buffer(&data); + buffer.open(QIODevice::WriteOnly); + pic.save(&buffer); + buffer.close(); + tox_set_avatar(tox, TOX_AVATARFORMAT_PNG, (uint8_t*)data.constData(), data.size()); + emit selfAvatarChanged(pic); + } + else + qDebug() << "Core: Error loading self avatar"; + bootstrapDht(); toxTimer->start(tox_do_interval(tox)); @@ -433,6 +449,18 @@ void Core::onFileDataCallback(Tox*, int32_t friendnumber, uint8_t filenumber, co file->filesize, file->bytesSent, ToxFile::RECEIVING); } +void Core::onAvatarInfoCallback(Tox* tox, int32_t friendnumber, uint8_t format, + uint8_t *hash, void *userdata) +{ + qDebug() << "Core: Got avatar info from "<0
- + 40 @@ -2093,7 +2093,7 @@ QSplitter:handle{ 0 0 263 - 373 + 378 @@ -3228,7 +3228,7 @@ QSplitter:handle{ 0 0 716 - 23 + 19
@@ -3254,6 +3254,11 @@ QSplitter:handle{ QLabel
widget/croppinglabel.h
+ + ClickableLabel + QLabel +
widget/tool/clickablelabel.h
+
diff --git a/qtox.pro b/qtox.pro index 68845488e..6b63a9835 100644 --- a/qtox.pro +++ b/qtox.pro @@ -116,7 +116,8 @@ HEADERS += widget/form/addfriendform.h \ widget/settingsdialog.h \ widget/tool/chatactions/messageaction.h \ widget/tool/chatactions/filetransferaction.h \ - widget/tool/chatactions/systemmessageaction.h + widget/tool/chatactions/systemmessageaction.h \ + widget/tool/clickablelabel.h SOURCES += \ widget/form/addfriendform.cpp \ diff --git a/settings.cpp b/settings.cpp index 6c039c6d2..f3a9e0d8b 100644 --- a/settings.cpp +++ b/settings.cpp @@ -27,6 +27,7 @@ #include const QString Settings::FILENAME = "settings.ini"; +const QString Settings::AVATAR_FILENAME = "avatar.dat"; bool Settings::makeToxPortable{false}; Settings::Settings() : @@ -257,6 +258,20 @@ QString Settings::getSettingsDirPath() #endif } +QPixmap Settings::getSavedAvatar() +{ + QString filePath = QDir(getSettingsDirPath()).filePath(AVATAR_FILENAME); + QPixmap pic; + pic.load(filePath); + return pic; +} + +void Settings::saveAvatar(QPixmap& pic) +{ + QString filePath = QDir(getSettingsDirPath()).filePath(AVATAR_FILENAME); + pic.save(filePath, "png"); +} + const QList& Settings::getDhtServerList() const { return dhtServerList; diff --git a/settings.h b/settings.h index 88811deb7..eb8f0e23c 100644 --- a/settings.h +++ b/settings.h @@ -19,6 +19,7 @@ #include #include +#include class Settings : public QObject { @@ -57,6 +58,9 @@ public: bool getEncryptLogs() const; void setEncryptLogs(bool newValue); + QPixmap getSavedAvatar(); + void saveAvatar(QPixmap& pic); + // Assume all widgets have unique names // Don't use it to save every single thing you want to save, use it // for some general purpose widgets, such as MainWindows or Splitters, @@ -138,6 +142,7 @@ private: Settings& operator=(const Settings&) = delete; static const QString FILENAME; + static const QString AVATAR_FILENAME; bool loaded; diff --git a/widget/tool/clickablelabel.h b/widget/tool/clickablelabel.h new file mode 100644 index 000000000..99e523b20 --- /dev/null +++ b/widget/tool/clickablelabel.h @@ -0,0 +1,22 @@ +#ifndef CLICKABLELABEL_H +#define CLICKABLELABEL_H + +#include + +class QMouseEvent; +class QWidget; + +class ClickableLabel : public QLabel +{ +Q_OBJECT + +public: + explicit ClickableLabel(QWidget* parent = 0) : QLabel(parent) {} +signals: + void clicked(); +protected: + void mousePressEvent (QMouseEvent*) {emit clicked();} +}; + + +#endif // CLICKABLELABEL_H diff --git a/widget/widget.cpp b/widget/widget.cpp index 64b09de80..5b5ba6c87 100644 --- a/widget/widget.cpp +++ b/widget/widget.cpp @@ -36,10 +36,12 @@ #include #include #include +#include #include #include #include #include +#include #include Widget *Widget::instance{nullptr}; @@ -180,6 +182,7 @@ Widget::Widget(QWidget *parent) connect(core, &Core::statusSet, this, &Widget::onStatusSet); connect(core, &Core::usernameSet, this, &Widget::setUsername); connect(core, &Core::statusMessageSet, this, &Widget::setStatusMessage); + connect(core, &Core::selfAvatarChanged, this, &Widget::onSelfAvatarLoaded); connect(core, SIGNAL(fileDownloadFinished(const QString&)), &filesForm, SLOT(onFileDownloadComplete(const QString&))); connect(core, SIGNAL(fileUploadFinished(const QString&)), &filesForm, SLOT(onFileUploadComplete(const QString&))); connect(core, &Core::friendAdded, this, &Widget::addFriend); @@ -210,6 +213,7 @@ Widget::Widget(QWidget *parent) connect(ui->settingsButton, SIGNAL(clicked()), this, SLOT(onSettingsClicked())); connect(ui->nameLabel, SIGNAL(textChanged(QString,QString)), this, SLOT(onUsernameChanged(QString,QString))); connect(ui->statusLabel, SIGNAL(textChanged(QString,QString)), this, SLOT(onStatusMessageChanged(QString,QString))); + connect(ui->profilePicture, SIGNAL(clicked()), this, SLOT(onAvatarClicked())); connect(setStatusOnline, SIGNAL(triggered()), this, SLOT(setStatusOnline())); connect(setStatusAway, SIGNAL(triggered()), this, SLOT(setStatusAway())); connect(setStatusBusy, SIGNAL(triggered()), this, SLOT(setStatusBusy())); @@ -271,6 +275,53 @@ Camera* Widget::getCamera() return camera; } +void Widget::onAvatarClicked() +{ + QString filename = QFileDialog::getOpenFileName(this, "Choose a profile picture"); + QFile file(filename); + file.open(QIODevice::ReadOnly); + if (!file.isOpen()) + { + QMessageBox::critical(this, "Error", "Unable to open this file"); + return; + } + + QPixmap pic; + if (!pic.loadFromData(file.readAll())) + { + QMessageBox::critical(this, "Error", "Unable to read this image"); + return; + } + + QByteArray bytes; + QBuffer buffer(&bytes); + buffer.open(QIODevice::WriteOnly); + pic.save(&buffer, "PNG"); + buffer.close(); + + if (bytes.size() >= TOX_MAX_AVATAR_DATA_LENGTH) + { + pic = pic.scaledToWidth(64, Qt::SmoothTransformation); + bytes.clear(); + buffer.open(QIODevice::WriteOnly); + pic.save(&buffer, "PNG"); + buffer.close(); + } + + if (bytes.size() >= TOX_MAX_AVATAR_DATA_LENGTH) + { + QMessageBox::critical(this, "Error", "This image is too big"); + return; + } + + core->setAvatar(TOX_AVATARFORMAT_PNG, bytes); +} + +void Widget::onSelfAvatarLoaded(const QPixmap& pic) +{ + ui->profilePicture->setPixmap(pic); +} + void Widget::onConnected() { ui->statusButton->setEnabled(true); diff --git a/widget/widget.h b/widget/widget.h index e85701a55..352e12cfa 100644 --- a/widget/widget.h +++ b/widget/widget.h @@ -80,6 +80,8 @@ private slots: void onTransferClicked(); void onSettingsClicked(); void onFailedToStartCore(); + void onAvatarClicked(); + void onSelfAvatarLoaded(const QPixmap &pic); void onUsernameChanged(const QString& newUsername, const QString& oldUsername); void onStatusMessageChanged(const QString& newStatusMessage, const QString& oldStatusMessage); void setUsername(const QString& username); From 8de71c19ed3f4a0dfb248ae78898fc148aa1abe1 Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Wed, 24 Sep 2014 17:28:38 +0200 Subject: [PATCH 050/205] Initial avatars support --- README.md | 1 + core.cpp | 30 ++++++++++++++++++++++-------- core.h | 1 + widget/form/chatform.cpp | 8 ++++++++ widget/form/chatform.h | 2 ++ widget/friendlistwidget.h | 1 + widget/friendwidget.cpp | 8 ++++++++ widget/friendwidget.h | 5 +++++ widget/widget.cpp | 4 +++- 9 files changed, 51 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 6f13e095a..39317b54a 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ However, it is not a fork. - Video calls - Tox DNS - Translations in various languages +- Avatars

Downloads

diff --git a/core.cpp b/core.cpp index d63461c07..e63ec890b 100644 --- a/core.cpp +++ b/core.cpp @@ -216,9 +216,10 @@ void Core::start() QByteArray data; QBuffer buffer(&data); buffer.open(QIODevice::WriteOnly); - pic.save(&buffer); + pic.save(&buffer, "PNG"); buffer.close(); - tox_set_avatar(tox, TOX_AVATARFORMAT_PNG, (uint8_t*)data.constData(), data.size()); + if (tox_set_avatar(tox, TOX_AVATARFORMAT_PNG, (uint8_t*)data.constData(), data.size()) != 0) + qWarning() << "Core:start: Error setting avatar, size:"<(core)->tox, friendId); + emit static_cast(core)->friendStatusChanged(friendId, status); } @@ -449,16 +454,25 @@ void Core::onFileDataCallback(Tox*, int32_t friendnumber, uint8_t filenumber, co file->filesize, file->bytesSent, ToxFile::RECEIVING); } -void Core::onAvatarInfoCallback(Tox* tox, int32_t friendnumber, uint8_t format, - uint8_t *hash, void *userdata) +void Core::onAvatarInfoCallback(Tox*, int32_t friendnumber, uint8_t format, + uint8_t *, void *) { - qDebug() << "Core: Got avatar info from "<(core)->friendAvatarChanged(friendnumber, pic); + } } void Core::acceptFriendRequest(const QString& userId) diff --git a/core.h b/core.h index 7c3a49a93..fb9207195 100644 --- a/core.h +++ b/core.h @@ -106,6 +106,7 @@ signals: void friendStatusMessageChanged(int friendId, const QString& message); void friendUsernameChanged(int friendId, const QString& username); void friendTypingChanged(int friendId, bool isTyping); + void friendAvatarChanged(int friendId, const QPixmap& pic); void friendStatusMessageLoaded(int friendId, const QString& message); void friendUsernameLoaded(int friendId, const QString& username); diff --git a/widget/form/chatform.cpp b/widget/form/chatform.cpp index f8b950b7b..6863107bb 100644 --- a/widget/form/chatform.cpp +++ b/widget/form/chatform.cpp @@ -464,3 +464,11 @@ void ChatForm::onFileSendFailed(int FriendId, const QString &fname) addSystemInfoMessage("File: \"" + fname + "\" failed to send.", "red"); } + +void ChatForm::onAvatarChange(int FriendId, const QPixmap &pic) +{ + if (FriendId != f->friendId) + return; + + avatarLabel->setPixmap(pic); +} diff --git a/widget/form/chatform.h b/widget/form/chatform.h index 43681562c..fd270fd64 100644 --- a/widget/form/chatform.h +++ b/widget/form/chatform.h @@ -23,6 +23,7 @@ struct Friend; class FileTransferInstance; class NetCamView; +class QPixmap; class ChatForm : public GenericChatForm { @@ -55,6 +56,7 @@ public slots: void onAvPeerTimeout(int FriendId, int CallId); void onAvMediaChange(int FriendId, int CallId, bool video); void onMicMuteToggle(); + void onAvatarChange(int FriendId, const QPixmap& pic); private slots: void onSendTriggered(); diff --git a/widget/friendlistwidget.h b/widget/friendlistwidget.h index dae6b1c61..f8c3adf8c 100644 --- a/widget/friendlistwidget.h +++ b/widget/friendlistwidget.h @@ -23,6 +23,7 @@ class QLayout; class QGridLayout; +class QPixmap; class FriendListWidget : public QWidget { diff --git a/widget/friendwidget.cpp b/widget/friendwidget.cpp index e1744002d..60b655c96 100644 --- a/widget/friendwidget.cpp +++ b/widget/friendwidget.cpp @@ -190,3 +190,11 @@ void FriendWidget::resetEventFlags() Friend* f = FriendList::findFriend(friendId); f->hasNewEvents = 0; } + +void FriendWidget::onAvatarChange(int FriendId, const QPixmap& pic) +{ + if (FriendId != friendId) + return; + + avatar.setPixmap(pic); +} diff --git a/widget/friendwidget.h b/widget/friendwidget.h index da158e68d..c693c6199 100644 --- a/widget/friendwidget.h +++ b/widget/friendwidget.h @@ -22,6 +22,8 @@ #include "genericchatroomwidget.h" #include "croppinglabel.h" +class QPixmap; + struct FriendWidget : public GenericChatroomWidget { Q_OBJECT @@ -39,6 +41,9 @@ signals: void removeFriend(int friendId); void copyFriendIdToClipboard(int friendId); +public slots: + void onAvatarChange(int FriendId, const QPixmap& pic); + public: int friendId; QLabel avatar, statusPic; diff --git a/widget/widget.cpp b/widget/widget.cpp index 5b5ba6c87..834a68412 100644 --- a/widget/widget.cpp +++ b/widget/widget.cpp @@ -168,6 +168,7 @@ Widget::Widget(QWidget *parent) qRegisterMetaType("uint8_t"); qRegisterMetaType("int32_t"); qRegisterMetaType("int64_t"); + qRegisterMetaType("QPixmap"); qRegisterMetaType("ToxFile"); qRegisterMetaType("ToxFile::FileDirection"); @@ -435,7 +436,6 @@ void Widget::setStatusMessage(const QString &statusMessage) void Widget::addFriend(int friendId, const QString &userId) { - qDebug() << "Widget: Adding friend with id "+userId; Friend* newfriend = FriendList::addFriend(friendId, userId); QLayout* layout = contactListWidget->getFriendLayout(Status::Offline); @@ -463,6 +463,8 @@ void Widget::addFriend(int friendId, const QString &userId) connect(core, &Core::avRequestTimeout, newfriend->chatForm, &ChatForm::onAvRequestTimeout); connect(core, &Core::avPeerTimeout, newfriend->chatForm, &ChatForm::onAvPeerTimeout); connect(core, &Core::avMediaChange, newfriend->chatForm, &ChatForm::onAvMediaChange); + connect(core, &Core::friendAvatarChanged, newfriend->chatForm, &ChatForm::onAvatarChange); + connect(core, &Core::friendAvatarChanged, newfriend->widget, &FriendWidget::onAvatarChange); } void Widget::addFriendFailed(const QString&) From 3cb1d280bc2e2f6ca2082cd9ab22264da6010d8b Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Wed, 24 Sep 2014 17:35:24 +0200 Subject: [PATCH 051/205] Fix avatars resetting after friend clicked on --- widget/friendwidget.cpp | 10 +++++++--- widget/friendwidget.h | 1 + 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/widget/friendwidget.cpp b/widget/friendwidget.cpp index 60b655c96..b9d134878 100644 --- a/widget/friendwidget.cpp +++ b/widget/friendwidget.cpp @@ -26,7 +26,7 @@ #include FriendWidget::FriendWidget(int FriendId, QString id) - : friendId(FriendId) + : friendId(FriendId), isDefaultAvatar{true} { setMouseTracking(true); setAutoFillBackground(true); @@ -134,7 +134,8 @@ void FriendWidget::setAsActiveChatroom() QPalette pal3; pal3.setColor(QPalette::Background, Qt::white); this->setPalette(pal3); - avatar.setPixmap(QPixmap(":img/contact_dark.png")); + if (isDefaultAvatar) + avatar.setPixmap(QPixmap(":img/contact_dark.png")); } void FriendWidget::setAsInactiveChatroom() @@ -153,7 +154,9 @@ void FriendWidget::setAsInactiveChatroom() QPalette pal3; pal3.setColor(QPalette::Background, QColor(65,65,65,255)); this->setPalette(pal3); - avatar.setPixmap(QPixmap(":img/contact.png")); + + if (isDefaultAvatar) + avatar.setPixmap(QPixmap(":img/contact.png")); } void FriendWidget::updateStatusLight() @@ -196,5 +199,6 @@ void FriendWidget::onAvatarChange(int FriendId, const QPixmap& pic) if (FriendId != friendId) return; + isDefaultAvatar = false; avatar.setPixmap(pic); } diff --git a/widget/friendwidget.h b/widget/friendwidget.h index c693c6199..a1bae68a1 100644 --- a/widget/friendwidget.h +++ b/widget/friendwidget.h @@ -48,6 +48,7 @@ public: int friendId; QLabel avatar, statusPic; CroppingLabel name, statusMessage; + bool isDefaultAvatar; }; #endif // FRIENDWIDGET_H From ab3f2e2950de8dd45baf0e70607ad033e200cf18 Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Wed, 24 Sep 2014 17:42:10 +0200 Subject: [PATCH 052/205] Rescale avatars in the friend widget --- widget/friendwidget.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/widget/friendwidget.cpp b/widget/friendwidget.cpp index b9d134878..fcb6a416f 100644 --- a/widget/friendwidget.cpp +++ b/widget/friendwidget.cpp @@ -200,5 +200,6 @@ void FriendWidget::onAvatarChange(int FriendId, const QPixmap& pic) return; isDefaultAvatar = false; - avatar.setPixmap(pic); + QPixmap scaled = pic.scaled(40,40,Qt::KeepAspectRatio,Qt::SmoothTransformation); + avatar.setPixmap(scaled); } From ff2994a0fd472e1008fdd39cfeb881d1d578d43d Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Wed, 24 Sep 2014 17:55:54 +0200 Subject: [PATCH 053/205] Cache avatars --- core.cpp | 5 +++-- settings.cpp | 8 ++++---- settings.h | 4 ++-- widget/widget.cpp | 8 ++++++++ 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/core.cpp b/core.cpp index e63ec890b..e0e4e2c43 100644 --- a/core.cpp +++ b/core.cpp @@ -210,7 +210,7 @@ void Core::start() tox_get_address(tox, friendAddress); emit friendAddressGenerated(CFriendAddress::toString(friendAddress)); - QPixmap pic = Settings::getInstance().getSavedAvatar(); + QPixmap pic = Settings::getInstance().getSavedAvatar(getSelfId().toString()); if (!pic.isNull() && !pic.size().isEmpty()) { QByteArray data; @@ -471,6 +471,7 @@ void Core::onAvatarDataCallback(Tox*, int32_t friendnumber, uint8_t, else { qDebug() << "Core: Got avatar data from "<(core)->getFriendAddress(friendnumber)); emit static_cast(core)->friendAvatarChanged(friendnumber, pic); } } @@ -783,7 +784,7 @@ void Core::setAvatar(uint8_t format, const QByteArray& data) QPixmap pic; pic.loadFromData(data); - Settings::getInstance().saveAvatar(pic); + Settings::getInstance().saveAvatar(pic, getSelfId().toString()); emit selfAvatarChanged(pic); } diff --git a/settings.cpp b/settings.cpp index f3a9e0d8b..0748cd0ff 100644 --- a/settings.cpp +++ b/settings.cpp @@ -258,17 +258,17 @@ QString Settings::getSettingsDirPath() #endif } -QPixmap Settings::getSavedAvatar() +QPixmap Settings::getSavedAvatar(const QString &ownerId) { - QString filePath = QDir(getSettingsDirPath()).filePath(AVATAR_FILENAME); + QString filePath = QDir(getSettingsDirPath()).filePath("avatar_"+ownerId); QPixmap pic; pic.load(filePath); return pic; } -void Settings::saveAvatar(QPixmap& pic) +void Settings::saveAvatar(QPixmap& pic, const QString& ownerId) { - QString filePath = QDir(getSettingsDirPath()).filePath(AVATAR_FILENAME); + QString filePath = QDir(getSettingsDirPath()).filePath("avatar_"+ownerId); pic.save(filePath, "png"); } diff --git a/settings.h b/settings.h index eb8f0e23c..882a31f0f 100644 --- a/settings.h +++ b/settings.h @@ -58,8 +58,8 @@ public: bool getEncryptLogs() const; void setEncryptLogs(bool newValue); - QPixmap getSavedAvatar(); - void saveAvatar(QPixmap& pic); + QPixmap getSavedAvatar(const QString& ownerId); + void saveAvatar(QPixmap& pic, const QString& ownerId); // Assume all widgets have unique names // Don't use it to save every single thing you want to save, use it diff --git a/widget/widget.cpp b/widget/widget.cpp index 834a68412..73b6946a2 100644 --- a/widget/widget.cpp +++ b/widget/widget.cpp @@ -465,6 +465,14 @@ void Widget::addFriend(int friendId, const QString &userId) connect(core, &Core::avMediaChange, newfriend->chatForm, &ChatForm::onAvMediaChange); connect(core, &Core::friendAvatarChanged, newfriend->chatForm, &ChatForm::onAvatarChange); connect(core, &Core::friendAvatarChanged, newfriend->widget, &FriendWidget::onAvatarChange); + + // Try to get the avatar from the cache + QPixmap avatar = Settings::getInstance().getSavedAvatar(userId); + if (!avatar.isNull()) + { + newfriend->chatForm->onAvatarChange(friendId, avatar); + newfriend->widget->onAvatarChange(friendId, avatar); + } } void Widget::addFriendFailed(const QString&) From 86e483303fe0ad6a2cab962b0582813180a7f004 Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Wed, 24 Sep 2014 18:22:09 +0200 Subject: [PATCH 054/205] Broadcast new avatars when changed --- core.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/core.cpp b/core.cpp index e0e4e2c43..2d0423a86 100644 --- a/core.cpp +++ b/core.cpp @@ -455,10 +455,12 @@ void Core::onFileDataCallback(Tox*, int32_t friendnumber, uint8_t filenumber, co } void Core::onAvatarInfoCallback(Tox*, int32_t friendnumber, uint8_t format, - uint8_t *, void *) + uint8_t *, void* core) { qDebug() << "Core: Got avatar info from "<(core)->tox, friendnumber); } void Core::onAvatarDataCallback(Tox*, int32_t friendnumber, uint8_t, @@ -786,6 +788,11 @@ void Core::setAvatar(uint8_t format, const QByteArray& data) pic.loadFromData(data); Settings::getInstance().saveAvatar(pic, getSelfId().toString()); emit selfAvatarChanged(pic); + + // Broadcast our new avatar! + const uint32_t friendCount = tox_count_friendlist(tox);; + for (unsigned i=0; i Date: Wed, 24 Sep 2014 18:25:09 +0200 Subject: [PATCH 055/205] Fix self avatar being cropped --- mainwindow.ui | 3 +++ widget/widget.cpp | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/mainwindow.ui b/mainwindow.ui index 83139cb6c..ff345391b 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -1471,6 +1471,9 @@ QSplitter:handle{ :/img/contact.png + + true + true diff --git a/widget/widget.cpp b/widget/widget.cpp index 73b6946a2..b2e1de6b5 100644 --- a/widget/widget.cpp +++ b/widget/widget.cpp @@ -320,7 +320,8 @@ void Widget::onAvatarClicked() void Widget::onSelfAvatarLoaded(const QPixmap& pic) { - ui->profilePicture->setPixmap(pic); + QPixmap scaled = pic.scaledToWidth(40, Qt::SmoothTransformation); + ui->profilePicture->setPixmap(scaled); } void Widget::onConnected() From 81e6d8323a8ad955ee998bb88e9167310f93ca64 Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Wed, 24 Sep 2014 18:32:20 +0200 Subject: [PATCH 056/205] Keep avatar aspect ratio --- widget/widget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/widget/widget.cpp b/widget/widget.cpp index b2e1de6b5..21f02feec 100644 --- a/widget/widget.cpp +++ b/widget/widget.cpp @@ -320,7 +320,7 @@ void Widget::onAvatarClicked() void Widget::onSelfAvatarLoaded(const QPixmap& pic) { - QPixmap scaled = pic.scaledToWidth(40, Qt::SmoothTransformation); + QPixmap scaled = pic.scaled(40,40, Qt::KeepAspectRatio,Qt::SmoothTransformation); ui->profilePicture->setPixmap(scaled); } From 52d18f9f18fc15dd70693d958c6db574bba2e1de Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Wed, 24 Sep 2014 18:40:40 +0200 Subject: [PATCH 057/205] Keep avatar aspect ratio (for real) --- mainwindow.ui | 2 +- widget/widget.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mainwindow.ui b/mainwindow.ui index ff345391b..845a0c728 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -1472,7 +1472,7 @@ QSplitter:handle{ :/img/contact.png - true + false true diff --git a/widget/widget.cpp b/widget/widget.cpp index 21f02feec..49e4fb10d 100644 --- a/widget/widget.cpp +++ b/widget/widget.cpp @@ -302,7 +302,7 @@ void Widget::onAvatarClicked() if (bytes.size() >= TOX_MAX_AVATAR_DATA_LENGTH) { - pic = pic.scaledToWidth(64, Qt::SmoothTransformation); + pic = pic.scaled(64,64, Qt::KeepAspectRatio, Qt::SmoothTransformation); bytes.clear(); buffer.open(QIODevice::WriteOnly); pic.save(&buffer, "PNG"); From be7c39d69ac7734ed32d156e0bb14a0221e88280 Mon Sep 17 00:00:00 2001 From: dubslow Date: Thu, 25 Sep 2014 09:55:36 -0500 Subject: [PATCH 058/205] api update --- core.cpp | 2 +- widget/widget.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core.cpp b/core.cpp index 2d0423a86..b2718ef5f 100644 --- a/core.cpp +++ b/core.cpp @@ -218,7 +218,7 @@ void Core::start() buffer.open(QIODevice::WriteOnly); pic.save(&buffer, "PNG"); buffer.close(); - if (tox_set_avatar(tox, TOX_AVATARFORMAT_PNG, (uint8_t*)data.constData(), data.size()) != 0) + if (tox_set_avatar(tox, TOX_AVATAR_FORMAT_PNG, (uint8_t*)data.constData(), data.size()) != 0) qWarning() << "Core:start: Error setting avatar, size:"<= TOX_MAX_AVATAR_DATA_LENGTH) + if (bytes.size() >= TOX_AVATAR_MAX_DATA_LENGTH) { pic = pic.scaled(64,64, Qt::KeepAspectRatio, Qt::SmoothTransformation); bytes.clear(); @@ -309,13 +309,13 @@ void Widget::onAvatarClicked() buffer.close(); } - if (bytes.size() >= TOX_MAX_AVATAR_DATA_LENGTH) + if (bytes.size() >= TOX_AVATAR_MAX_DATA_LENGTH) { QMessageBox::critical(this, "Error", "This image is too big"); return; } - core->setAvatar(TOX_AVATARFORMAT_PNG, bytes); + core->setAvatar(TOX_AVATAR_FORMAT_PNG, bytes); } void Widget::onSelfAvatarLoaded(const QPixmap& pic) From e32ad7236825384eed7b97ccfa3992f8ee0d8de2 Mon Sep 17 00:00:00 2001 From: dubslow Date: Thu, 25 Sep 2014 10:16:36 -0500 Subject: [PATCH 059/205] slight improvements to avatars --- widget/widget.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/widget/widget.cpp b/widget/widget.cpp index aa4a5cff0..88128d8ac 100644 --- a/widget/widget.cpp +++ b/widget/widget.cpp @@ -278,19 +278,21 @@ Camera* Widget::getCamera() void Widget::onAvatarClicked() { - QString filename = QFileDialog::getOpenFileName(this, "Choose a profile picture"); + QString filename = QFileDialog::getOpenFileName(this, tr("Choose a profile picture"), QDir::homePath(), "*.png"); + if (filename == "") + return; QFile file(filename); file.open(QIODevice::ReadOnly); if (!file.isOpen()) { - QMessageBox::critical(this, "Error", "Unable to open this file"); + QMessageBox::critical(this, tr("Error"), tr("Unable to open this file")); return; } QPixmap pic; if (!pic.loadFromData(file.readAll())) { - QMessageBox::critical(this, "Error", "Unable to read this image"); + QMessageBox::critical(this, tr("Error"), tr("Unable to read this image")); return; } @@ -311,7 +313,7 @@ void Widget::onAvatarClicked() if (bytes.size() >= TOX_AVATAR_MAX_DATA_LENGTH) { - QMessageBox::critical(this, "Error", "This image is too big"); + QMessageBox::critical(this, tr("Error"), tr("This image is too big")); return; } From 458636e6d6bcb48c8ac914df6050578fe9db0cbb Mon Sep 17 00:00:00 2001 From: krepa098 Date: Thu, 25 Sep 2014 15:38:47 +0200 Subject: [PATCH 060/205] EmoticonsWidget: use HandCursor --- widget/emoticonswidget.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/widget/emoticonswidget.cpp b/widget/emoticonswidget.cpp index bab7abe8d..f471e8729 100644 --- a/widget/emoticonswidget.cpp +++ b/widget/emoticonswidget.cpp @@ -66,6 +66,7 @@ EmoticonsWidget::EmoticonsWidget(QWidget *parent) : { QRadioButton* pageButton = new QRadioButton; pageButton->setProperty("pageIndex", i); + pageButton->setCursor(Qt::PointingHandCursor); pageButton->setChecked(i == 0); buttonLayout->addWidget(pageButton); @@ -80,6 +81,7 @@ EmoticonsWidget::EmoticonsWidget(QWidget *parent) : button->setIcon(SmileyPack::getInstance().getAsIcon(set[0])); button->setToolTip(set.join(" ")); button->setProperty("sequence", set[0]); + button->setCursor(Qt::PointingHandCursor); button->setFlat(true); connect(button, &QPushButton::clicked, this, &EmoticonsWidget::onSmileyClicked); From ad5a175f7d0c1c8294dc0ce311e8b2c63256e0b7 Mon Sep 17 00:00:00 2001 From: krepa098 Date: Thu, 25 Sep 2014 18:03:25 +0200 Subject: [PATCH 061/205] drag&drop support --- widget/form/chatform.cpp | 25 +++++++++++++++++++++++++ widget/form/chatform.h | 5 +++++ widget/form/genericchatform.cpp | 18 ++++++------------ widget/form/genericchatform.h | 9 ++++----- widget/form/groupchatform.cpp | 24 ++++++++++++++++++++---- widget/form/groupchatform.h | 7 ++++++- widget/friendwidget.cpp | 28 ++++++++++++++++++++++++++++ widget/friendwidget.h | 5 +++++ 8 files changed, 99 insertions(+), 22 deletions(-) diff --git a/widget/form/chatform.cpp b/widget/form/chatform.cpp index 6863107bb..788596dd6 100644 --- a/widget/form/chatform.cpp +++ b/widget/form/chatform.cpp @@ -19,6 +19,9 @@ #include #include #include +#include +#include +#include #include "chatform.h" #include "friend.h" #include "widget/friendwidget.h" @@ -52,6 +55,8 @@ ChatForm::ChatForm(Friend* chatFriend) connect(micButton, SIGNAL(clicked()), this, SLOT(onMicMuteToggle())); connect(chatWidget, &ChatAreaWidget::onFileTranfertInterract, this, &ChatForm::onFileTansBtnClicked); connect(Core::getInstance(), &Core::fileSendFailed, this, &ChatForm::onFileSendFailed); + + setAcceptDrops(true); } ChatForm::~ChatForm() @@ -472,3 +477,23 @@ void ChatForm::onAvatarChange(int FriendId, const QPixmap &pic) avatarLabel->setPixmap(pic); } + +void ChatForm::dragEnterEvent(QDragEnterEvent *ev) +{ + if (ev->mimeData()->hasUrls()) + ev->acceptProposedAction(); +} + +void ChatForm::dropEvent(QDropEvent *ev) +{ + if (ev->mimeData()->hasUrls()) + { + for (QUrl url : ev->mimeData()->urls()) + { + QFileInfo info(url.path()); + + if (info.exists()) + Core::getInstance()->sendFile(f->friendId, info.fileName(), info.absoluteFilePath(), info.size()); + } + } +} diff --git a/widget/form/chatform.h b/widget/form/chatform.h index fd270fd64..4604d54e3 100644 --- a/widget/form/chatform.h +++ b/widget/form/chatform.h @@ -69,6 +69,11 @@ private slots: void onFileTansBtnClicked(QString widgetName, QString buttonName); void onFileSendFailed(int FriendId, const QString &fname); +protected: + // drag & drop + void dragEnterEvent(QDragEnterEvent* ev); + void dropEvent(QDropEvent* ev); + private: Friend* f; CroppingLabel *statusMessageLabel; diff --git a/widget/form/genericchatform.cpp b/widget/form/genericchatform.cpp index 0e765b397..cff9e3b50 100644 --- a/widget/form/genericchatform.cpp +++ b/widget/form/genericchatform.cpp @@ -27,12 +27,12 @@ #include "widget/chatareawidget.h" #include "widget/tool/chattextedit.h" -GenericChatForm::GenericChatForm(QObject *parent) : - QObject(parent) +GenericChatForm::GenericChatForm(QWidget *parent) : + QWidget(parent) { curRow = 0; - mainWidget = new QWidget(); headWidget = new QWidget(); + headWidget = new QWidget(); nameLabel = new CroppingLabel(); avatarLabel = new QLabel(); @@ -84,7 +84,7 @@ GenericChatForm::GenericChatForm(QObject *parent) : micButton->setObjectName("green"); micButton->setStyleSheet(micButtonStylesheet); - mainWidget->setLayout(mainLayout); + setLayout(mainLayout); mainLayout->addWidget(chatWidget); mainLayout->addLayout(mainFootLayout); mainLayout->setMargin(0); @@ -129,10 +129,10 @@ void GenericChatForm::setName(const QString &newName) void GenericChatForm::show(Ui::MainWindow &ui) { - ui.mainContent->layout()->addWidget(mainWidget); + ui.mainContent->layout()->addWidget(this); ui.mainHead->layout()->addWidget(headWidget); - mainWidget->show(); headWidget->show(); + QWidget::show(); } void GenericChatForm::onChatContextMenuRequested(QPoint pos) @@ -172,12 +172,6 @@ void GenericChatForm::addMessage(QString author, QString message, QDateTime date previousName = author; } -GenericChatForm::~GenericChatForm() -{ - delete mainWidget; - delete headWidget; -} - void GenericChatForm::onEmoteButtonClicked() { // don't show the smiley selection widget if there are no smileys available diff --git a/widget/form/genericchatform.h b/widget/form/genericchatform.h index 72dc94fd9..c824d5e85 100644 --- a/widget/form/genericchatform.h +++ b/widget/form/genericchatform.h @@ -17,7 +17,7 @@ #ifndef GENERICCHATFORM_H #define GENERICCHATFORM_H -#include +#include #include #include @@ -35,12 +35,11 @@ namespace Ui { class MainWindow; } -class GenericChatForm : public QObject +class GenericChatForm : public QWidget { Q_OBJECT public: - GenericChatForm(QObject *parent = 0); - virtual ~GenericChatForm(); + GenericChatForm(QWidget *parent = 0); virtual void setName(const QString &newName); virtual void show(Ui::MainWindow &ui); @@ -62,7 +61,7 @@ protected slots: protected: CroppingLabel *nameLabel; QLabel *avatarLabel; - QWidget *mainWidget, *headWidget; + QWidget *headWidget; QPushButton *fileButton, *emoteButton, *callButton, *videoButton, *volButton, *micButton; QVBoxLayout *headTextLayout; ChatTextEdit *msgEdit; diff --git a/widget/form/groupchatform.cpp b/widget/form/groupchatform.cpp index 907787fd3..4dc6c7e0d 100644 --- a/widget/form/groupchatform.cpp +++ b/widget/form/groupchatform.cpp @@ -19,7 +19,10 @@ #include "widget/groupwidget.h" #include "widget/tool/chattextedit.h" #include "widget/croppinglabel.h" +#include "core.h" #include +#include +#include GroupChatForm::GroupChatForm(Group* chatGroup) : group(chatGroup) @@ -58,11 +61,8 @@ GroupChatForm::GroupChatForm(Group* chatGroup) connect(sendButton, SIGNAL(clicked()), this, SLOT(onSendTriggered())); connect(msgEdit, SIGNAL(enterPressed()), this, SLOT(onSendTriggered())); -} - -GroupChatForm::~GroupChatForm() -{ + setAcceptDrops(true); } void GroupChatForm::onSendTriggered() @@ -94,3 +94,19 @@ void GroupChatForm::onUserListChanged() names.chop(2); namesList->setText(names); } + +void GroupChatForm::dragEnterEvent(QDragEnterEvent *ev) +{ + if (ev->mimeData()->hasFormat("friend")) + ev->acceptProposedAction(); +} + +void GroupChatForm::dropEvent(QDropEvent *ev) +{ + if (ev->mimeData()->hasFormat("friend")) + { + int friendId = ev->mimeData()->data("friend").toInt(); + Core::getInstance()->groupInviteFriend(friendId, group->groupId); + } +} + diff --git a/widget/form/groupchatform.h b/widget/form/groupchatform.h index cdf20a113..a544034de 100644 --- a/widget/form/groupchatform.h +++ b/widget/form/groupchatform.h @@ -27,13 +27,18 @@ class GroupChatForm : public GenericChatForm Q_OBJECT public: GroupChatForm(Group* chatGroup); - ~GroupChatForm(); + void addGroupMessage(QString message, int peerId); void onUserListChanged(); private slots: void onSendTriggered(); +protected: + // drag & drop + void dragEnterEvent(QDragEnterEvent* ev); + void dropEvent(QDropEvent* ev); + private: Group* group; QLabel *nusersLabel, *namesList; diff --git a/widget/friendwidget.cpp b/widget/friendwidget.cpp index fcb6a416f..869bc4192 100644 --- a/widget/friendwidget.cpp +++ b/widget/friendwidget.cpp @@ -24,6 +24,9 @@ #include "widget/form/chatform.h" #include #include +#include +#include +#include FriendWidget::FriendWidget(int FriendId, QString id) : friendId(FriendId), isDefaultAvatar{true} @@ -203,3 +206,28 @@ void FriendWidget::onAvatarChange(int FriendId, const QPixmap& pic) QPixmap scaled = pic.scaled(40,40,Qt::KeepAspectRatio,Qt::SmoothTransformation); avatar.setPixmap(scaled); } + +void FriendWidget::mousePressEvent(QMouseEvent *ev) +{ + if (ev->button() == Qt::LeftButton) + dragStartPos = ev->pos(); +} + +void FriendWidget::mouseMoveEvent(QMouseEvent *ev) +{ + if (!(ev->buttons() & Qt::LeftButton)) + return; + + if ((dragStartPos - ev->pos()).manhattanLength() > QApplication::startDragDistance()) + { + QDrag* drag = new QDrag(this); + QMimeData* mdata = new QMimeData; + mdata->setData("friend", QString::number(friendId).toLatin1()); + + drag->setMimeData(mdata); + if (avatar.pixmap()) + drag->setPixmap(*avatar.pixmap()); + + drag->exec(Qt::CopyAction | Qt::MoveAction); + } +} diff --git a/widget/friendwidget.h b/widget/friendwidget.h index a1bae68a1..aa225d533 100644 --- a/widget/friendwidget.h +++ b/widget/friendwidget.h @@ -44,11 +44,16 @@ signals: public slots: void onAvatarChange(int FriendId, const QPixmap& pic); +protected: + void mousePressEvent(QMouseEvent* ev); + void mouseMoveEvent(QMouseEvent* ev); + public: int friendId; QLabel avatar, statusPic; CroppingLabel name, statusMessage; bool isDefaultAvatar; + QPoint dragStartPos; }; #endif // FRIENDWIDGET_H From 46ffc883df94b2fb664e3bed1644cfe53b890bf8 Mon Sep 17 00:00:00 2001 From: apprb Date: Fri, 26 Sep 2014 00:30:23 +0700 Subject: [PATCH 062/205] Progress bar in file transfers (fix #309) --- filetransferinstance.cpp | 34 ++++++++++++++++++++++++++++++---- filetransferinstance.h | 3 ++- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/filetransferinstance.cpp b/filetransferinstance.cpp index 9bcc7b6e1..6167bfac3 100644 --- a/filetransferinstance.cpp +++ b/filetransferinstance.cpp @@ -21,6 +21,7 @@ #include #include #include +#include uint FileTransferInstance::Idconter = 0; @@ -76,6 +77,7 @@ void FileTransferInstance::onFileTransferInfo(int FriendId, int FileNum, int64_t long rawspeed = diff / timediff; speed = getHumanReadableSize(rawspeed)+"/s"; size = getHumanReadableSize(Filesize); + totalBytes = Filesize; if (!rawspeed) return; int etaSecs = (Filesize - BytesSent) / rawspeed; @@ -352,8 +354,16 @@ QString FileTransferInstance::draw2ButtonsForm(const QString &type, const QImage QString imgBstr = ""; QString content; - content += "

" + filename + "

"; - content += "

" + getHumanReadableSize(lastBytesSent) + " / " + size + " (" + speed + " ETA: " + eta + ")

\n"; + QString progrBar = ""; + + content = "

" + filename + "

"; + content += ""; + content += ""; + content += ""; + content += ""; + content += "
" + size + "" + speed + "ETA: " + eta + "
"; + content += progrBar; + content += "
"; return wrapIntoForm(content, type, imgAstr, imgBstr); } @@ -362,10 +372,10 @@ QString FileTransferInstance::wrapIntoForm(const QString& content, const QString { QString res; - res = "\n"; + res = "
\n"; res += "\n"; res += insertMiniature(type); - res += "
\n"; + res += "\n"; res += "
"; res += content; res += "
\n"; @@ -378,3 +388,19 @@ QString FileTransferInstance::wrapIntoForm(const QString& content, const QString return res; } + +QImage FileTransferInstance::drawProgressBarImg(const double &part, int w, int h) +{ + QImage progressBar(w, h, QImage::Format_Mono); + + QPainter qPainter(&progressBar); + qPainter.setBrush(Qt::NoBrush); + qPainter.setPen(Qt::black); + qPainter.drawRect(0, 0, w - 1, h - 1); + + qPainter.setBrush(Qt::SolidPattern); + qPainter.setPen(Qt::black); + qPainter.drawRect(1, 0, (w - 2) * (part), h - 1); + + return progressBar; +} diff --git a/filetransferinstance.h b/filetransferinstance.h index b81b03102..d1c9062d9 100644 --- a/filetransferinstance.h +++ b/filetransferinstance.h @@ -62,6 +62,7 @@ private: QString draw2ButtonsForm(const QString &type, const QImage &imgA, const QImage &imgB); QString insertMiniature(const QString &type); QString wrapIntoForm(const QString &content, const QString &type, const QString &imgAstr, const QString &imgBstr); + QImage drawProgressBarImg(const double &part, int w, int h); private: static uint Idconter; @@ -72,7 +73,7 @@ private: QImage pic; QString filename, size, speed, eta; QDateTime lastUpdate; - long long lastBytesSent; + long long lastBytesSent, totalBytes; int fileNum; int friendId; QString savePath; From ca05c2a024cd3c705477132be6fa7d6ccbf3a10f Mon Sep 17 00:00:00 2001 From: Ansa89 Date: Fri, 26 Sep 2014 10:38:18 +0200 Subject: [PATCH 063/205] Italian translation: update --- translations/it.qm | Bin 7125 -> 7641 bytes translations/it.ts | 71 +++++++++++++++++++++++++++++++-------------- 2 files changed, 49 insertions(+), 22 deletions(-) diff --git a/translations/it.qm b/translations/it.qm index b61df4ac4e148c46c9e020b5a5d38bbd1a45673e..179823b08a782188749dffc9c18478eb15acdf03 100644 GIT binary patch delta 582 zcmZutJxjwt7=EI(ji6Sfh1M=N__21Vh$sk3MZrZ>1Q$u{H9bgs@ft^|vmjVP2XS!l zC#a*Ki-Utx3%WTv^e>3MmqM$h90&J2$@_e~t%Z-J%Y@<8liPD!S2mEo$3c4@h_`Y5 z-2@V^xH*gf#)ugUE{v=>@}u$u-h)Tu zHlEoS1~83va43|6r=i)q#?VB%wu&7b5$V8%0K*9?n4?#jjzz2>%!&8HK}OgOk%B}q zMA9T>MCqp1N>WxivzVu3QMjCW;>bTyoI)YGFA5I#4V_~Yc}k%rCKY&hK9W~Ts-Tfs ztm(gU*cuq+ivsxJv`4WdA%~DfK?{GxlDj2QWuk03oYBLVlG(!PPm;qX71b(LIs$fB ziPuQfB3coogoHZ1JB@pZQ+pN5rk=iJ(&H88Yfs(0-)DKS4+*>B@||$K+Q`+Nv;X(s T-B7ycr?^$<`00+pb0+Z%`^ ChatForm - + Send a file Invia un file @@ -113,19 +113,19 @@ FileTransferInstance - + Save a file Title of the file saving dialog Salva file - + Location not writable Title of permissions popup Errore - + You do not have permission to write that location. Choose another, or cancel the save dialog. text of permissions popup Non hai sufficienti permessi per scrivere in questa locazione. Scegli un'altra posizione, o annulla il salvataggio. @@ -189,19 +189,19 @@ FriendWidget - + Copy friend ID Menu to copy the Tox ID of that friend Copia Tox ID del contatto - + Invite in group Menu to invite a friend in a groupchat Invita nel gruppo - + Remove friend Menu to remove the friend from our friendlist Rimuovi contatto @@ -252,8 +252,8 @@ GenericChatForm - - + + Save chat log Salva il log della chat @@ -261,7 +261,7 @@ GroupChatForm - + %1 users in chat Number of users in chat %1 utenti in chat @@ -336,42 +336,42 @@ qTox - + Your name qTox User - + Your status Toxing on qTox - + Add friends Aggiungi contatto - + Create a group chat Crea un gruppo - + View completed file transfers Visualizza i trasferimenti completati - + Change your settings Cambia le impostazioni - + Close Chiudi - + Ctrl+Q Ctrl+Q @@ -431,25 +431,52 @@ Widget - + Online Button to set your status to 'Online' Online - + Away Button to set your status to 'Away' Assente - + Busy Button to set your status to 'Busy' Occupato - + + Choose a profile picture + Scegli un'immagine per il profilo + + + + + + Error + Errore + + + + Unable to open this file + Impossibile aprire il file + + + + Unable to read this image + Impossibile leggere l'immagine + + + + This image is too big + L'immagine è troppo grande + + + <Unknown> Placeholder when we don't know someone's name in a group chat <Sconosciuto> From 5e90955e7d12125e5ffb18e5556036f70456b61c Mon Sep 17 00:00:00 2001 From: apprb Date: Fri, 26 Sep 2014 19:17:27 +0700 Subject: [PATCH 064/205] ChatForm: avatar scale --- widget/form/chatform.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/widget/form/chatform.cpp b/widget/form/chatform.cpp index 788596dd6..83f9a9892 100644 --- a/widget/form/chatform.cpp +++ b/widget/form/chatform.cpp @@ -475,7 +475,8 @@ void ChatForm::onAvatarChange(int FriendId, const QPixmap &pic) if (FriendId != f->friendId) return; - avatarLabel->setPixmap(pic); + QPixmap scaled = pic.scaled(40,40,Qt::KeepAspectRatio,Qt::SmoothTransformation); + avatarLabel->setPixmap(scaled); } void ChatForm::dragEnterEvent(QDragEnterEvent *ev) From 5662aa933f1beb6c0fe58b3d6a7b84c6cf06e999 Mon Sep 17 00:00:00 2001 From: krepa098 Date: Fri, 26 Sep 2014 16:39:29 +0200 Subject: [PATCH 065/205] Added MaskablePixmapWidget, improved avatar rendering --- img/avatar_mask.png | Bin 0 -> 5766 bytes img/avatar_mask_circle.png | Bin 0 -> 9310 bytes mainwindow.ui | 51 +++++++++----------------- qtox.pro | 5 +-- res.qrc | 2 ++ widget/form/chatform.cpp | 7 ++-- widget/form/genericchatform.cpp | 5 +-- widget/form/genericchatform.h | 3 +- widget/form/groupchatform.cpp | 3 +- widget/friendwidget.cpp | 17 ++++----- widget/friendwidget.h | 4 ++- widget/maskablepixmapwidget.cpp | 61 ++++++++++++++++++++++++++++++++ widget/maskablepixmapwidget.h | 45 +++++++++++++++++++++++ widget/tool/clickablelabel.h | 22 ------------ widget/widget.cpp | 10 ++++-- widget/widget.h | 2 ++ 16 files changed, 160 insertions(+), 77 deletions(-) create mode 100644 img/avatar_mask.png create mode 100644 img/avatar_mask_circle.png create mode 100644 widget/maskablepixmapwidget.cpp create mode 100644 widget/maskablepixmapwidget.h delete mode 100644 widget/tool/clickablelabel.h diff --git a/img/avatar_mask.png b/img/avatar_mask.png new file mode 100644 index 0000000000000000000000000000000000000000..508914f0425838a3c1b5496ff87ff6388115ace3 GIT binary patch literal 5766 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 gWr(=7(0;p!HfY`X17htZas?mKQK?1qW}N^ literal 0 HcmV?d00001 diff --git a/img/avatar_mask_circle.png b/img/avatar_mask_circle.png new file mode 100644 index 0000000000000000000000000000000000000000..83cb97dfc4e3874237965d1d0a961bd1cbb91592 GIT binary patch literal 9310 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 literal 0 HcmV?d00001 diff --git a/mainwindow.ui b/mainwindow.ui index 845a0c728..a197594bd 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -6,8 +6,8 @@ 0 0 - 716 - 543 + 714 + 541 @@ -1452,32 +1452,20 @@ QSplitter:handle{ 0 - - + + + Qt::Horizontal + + + QSizePolicy::Maximum + + - 40 - 40 + 5 + 20 - - - 40 - 40 - - - - - - - :/img/contact.png - - - false - - - true - - + @@ -2095,8 +2083,8 @@ QSplitter:handle{ 0 0 - 263 - 378 + 262 + 375 @@ -3230,8 +3218,8 @@ QSplitter:handle{ 0 0 - 716 - 19 + 714 + 25 @@ -3257,11 +3245,6 @@ QSplitter:handle{ QLabel
widget/croppinglabel.h
- - ClickableLabel - QLabel -
widget/tool/clickablelabel.h
-
diff --git a/qtox.pro b/qtox.pro index 6b63a9835..c5bf81c1b 100644 --- a/qtox.pro +++ b/qtox.pro @@ -117,7 +117,7 @@ HEADERS += widget/form/addfriendform.h \ widget/tool/chatactions/messageaction.h \ widget/tool/chatactions/filetransferaction.h \ widget/tool/chatactions/systemmessageaction.h \ - widget/tool/clickablelabel.h + widget/maskablepixmapwidget.h SOURCES += \ widget/form/addfriendform.cpp \ @@ -157,4 +157,5 @@ SOURCES += \ widget/settingsdialog.cpp \ widget/tool/chatactions/messageaction.cpp \ widget/tool/chatactions/filetransferaction.cpp \ - widget/tool/chatactions/systemmessageaction.cpp + widget/tool/chatactions/systemmessageaction.cpp \ + widget/maskablepixmapwidget.cpp diff --git a/res.qrc b/res.qrc index b1b50df58..62b891ee6 100644 --- a/res.qrc +++ b/res.qrc @@ -142,5 +142,7 @@ translations/pl.qm translations/fi.qm translations/mannol.qm + img/avatar_mask.png + img/avatar_mask_circle.png diff --git a/widget/form/chatform.cpp b/widget/form/chatform.cpp index 83f9a9892..f659240da 100644 --- a/widget/form/chatform.cpp +++ b/widget/form/chatform.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include "chatform.h" #include "friend.h" #include "widget/friendwidget.h" @@ -32,12 +33,13 @@ #include "widget/tool/chattextedit.h" #include "core.h" #include "widget/widget.h" +#include "widget/maskablepixmapwidget.h" ChatForm::ChatForm(Friend* chatFriend) : f(chatFriend) { nameLabel->setText(f->getName()); - avatarLabel->setPixmap(QPixmap(":/img/contact_dark.png")); + avatar->setPixmap(QPixmap(":/img/contact_dark.png")); statusMessageLabel = new CroppingLabel(); netcam = new NetCamView(); @@ -475,8 +477,7 @@ void ChatForm::onAvatarChange(int FriendId, const QPixmap &pic) if (FriendId != f->friendId) return; - QPixmap scaled = pic.scaled(40,40,Qt::KeepAspectRatio,Qt::SmoothTransformation); - avatarLabel->setPixmap(scaled); + avatar->setPixmap(pic); } void ChatForm::dragEnterEvent(QDragEnterEvent *ev) diff --git a/widget/form/genericchatform.cpp b/widget/form/genericchatform.cpp index cff9e3b50..1f7b827f7 100644 --- a/widget/form/genericchatform.cpp +++ b/widget/form/genericchatform.cpp @@ -26,6 +26,7 @@ #include "widget/tool/chatactions/systemmessageaction.h" #include "widget/chatareawidget.h" #include "widget/tool/chattextedit.h" +#include "widget/maskablepixmapwidget.h" GenericChatForm::GenericChatForm(QWidget *parent) : QWidget(parent) @@ -35,7 +36,7 @@ GenericChatForm::GenericChatForm(QWidget *parent) : headWidget = new QWidget(); nameLabel = new CroppingLabel(); - avatarLabel = new QLabel(); + avatar = new MaskablePixmapWidget(this, QSize(40,40), ":/img/avatar_mask_circle.png"); QHBoxLayout *headLayout = new QHBoxLayout(), *mainFootLayout = new QHBoxLayout(); headTextLayout = new QVBoxLayout(); QVBoxLayout *mainLayout = new QVBoxLayout(); @@ -99,7 +100,7 @@ GenericChatForm::GenericChatForm(QWidget *parent) : mainFootLayout->setSpacing(0); headWidget->setLayout(headLayout); - headLayout->addWidget(avatarLabel); + headLayout->addWidget(avatar); headLayout->addLayout(headTextLayout); headLayout->addLayout(volMicLayout); headLayout->addWidget(callButton); diff --git a/widget/form/genericchatform.h b/widget/form/genericchatform.h index c824d5e85..d45bf1072 100644 --- a/widget/form/genericchatform.h +++ b/widget/form/genericchatform.h @@ -30,6 +30,7 @@ class QPushButton; class CroppingLabel; class ChatTextEdit; class ChatAreaWidget; +class MaskablePixmapWidget; namespace Ui { class MainWindow; @@ -60,7 +61,7 @@ protected slots: protected: CroppingLabel *nameLabel; - QLabel *avatarLabel; + MaskablePixmapWidget *avatar; QWidget *headWidget; QPushButton *fileButton, *emoteButton, *callButton, *videoButton, *volButton, *micButton; QVBoxLayout *headTextLayout; diff --git a/widget/form/groupchatform.cpp b/widget/form/groupchatform.cpp index 4dc6c7e0d..7622f2cf0 100644 --- a/widget/form/groupchatform.cpp +++ b/widget/form/groupchatform.cpp @@ -19,6 +19,7 @@ #include "widget/groupwidget.h" #include "widget/tool/chattextedit.h" #include "widget/croppinglabel.h" +#include "widget/maskablepixmapwidget.h" #include "core.h" #include #include @@ -42,7 +43,7 @@ GroupChatForm::GroupChatForm(Group* chatGroup) nameLabel->setText(group->widget->name.text()); nusersLabel->setFont(small); nusersLabel->setText(GroupChatForm::tr("%1 users in chat","Number of users in chat").arg(group->peers.size())); - avatarLabel->setPixmap(QPixmap(":/img/group_dark.png")); + avatar->setPixmap(QPixmap(":/img/group_dark.png")); QString names; for (QString& s : group->peers) diff --git a/widget/friendwidget.cpp b/widget/friendwidget.cpp index 869bc4192..c15ee03cc 100644 --- a/widget/friendwidget.cpp +++ b/widget/friendwidget.cpp @@ -22,11 +22,13 @@ #include "friend.h" #include "core.h" #include "widget/form/chatform.h" +#include "widget/maskablepixmapwidget.h" #include #include #include #include #include +#include FriendWidget::FriendWidget(int FriendId, QString id) : friendId(FriendId), isDefaultAvatar{true} @@ -42,7 +44,8 @@ FriendWidget::FriendWidget(int FriendId, QString id) textLayout.setMargin(0); setLayoutDirection(Qt::LeftToRight); // parent might have set Qt::RightToLeft - avatar.setPixmap(QPixmap(":img/contact.png")); + avatar = new MaskablePixmapWidget(this, QSize(40,40), ":/img/avatar_mask.png"); + avatar->setPixmap(QPixmap(":img/contact.png")); name.setText(id); //statusPic.setAlignment(Qt::AlignHCenter); statusPic.setPixmap(QPixmap(":img/status/dot_away.png")); @@ -65,7 +68,7 @@ FriendWidget::FriendWidget(int FriendId, QString id) textLayout.addStretch(); layout.addSpacing(20); - layout.addWidget(&avatar); + layout.addWidget(avatar); layout.addSpacing(5); layout.addLayout(&textLayout); layout.addSpacing(5); @@ -138,7 +141,7 @@ void FriendWidget::setAsActiveChatroom() pal3.setColor(QPalette::Background, Qt::white); this->setPalette(pal3); if (isDefaultAvatar) - avatar.setPixmap(QPixmap(":img/contact_dark.png")); + avatar->setPixmap(QPixmap(":img/contact_dark.png")); } void FriendWidget::setAsInactiveChatroom() @@ -159,7 +162,7 @@ void FriendWidget::setAsInactiveChatroom() this->setPalette(pal3); if (isDefaultAvatar) - avatar.setPixmap(QPixmap(":img/contact.png")); + avatar->setPixmap(QPixmap(":img/contact.png")); } void FriendWidget::updateStatusLight() @@ -203,8 +206,7 @@ void FriendWidget::onAvatarChange(int FriendId, const QPixmap& pic) return; isDefaultAvatar = false; - QPixmap scaled = pic.scaled(40,40,Qt::KeepAspectRatio,Qt::SmoothTransformation); - avatar.setPixmap(scaled); + avatar->setPixmap(pic); } void FriendWidget::mousePressEvent(QMouseEvent *ev) @@ -225,8 +227,7 @@ void FriendWidget::mouseMoveEvent(QMouseEvent *ev) mdata->setData("friend", QString::number(friendId).toLatin1()); drag->setMimeData(mdata); - if (avatar.pixmap()) - drag->setPixmap(*avatar.pixmap()); + drag->setPixmap(avatar->getPixmap()); drag->exec(Qt::CopyAction | Qt::MoveAction); } diff --git a/widget/friendwidget.h b/widget/friendwidget.h index aa225d533..4cfef368e 100644 --- a/widget/friendwidget.h +++ b/widget/friendwidget.h @@ -23,6 +23,7 @@ #include "croppinglabel.h" class QPixmap; +class MaskablePixmapWidget; struct FriendWidget : public GenericChatroomWidget { @@ -50,7 +51,8 @@ protected: public: int friendId; - QLabel avatar, statusPic; + MaskablePixmapWidget* avatar; + QLabel statusPic; CroppingLabel name, statusMessage; bool isDefaultAvatar; QPoint dragStartPos; diff --git a/widget/maskablepixmapwidget.cpp b/widget/maskablepixmapwidget.cpp new file mode 100644 index 000000000..6fdd3f03b --- /dev/null +++ b/widget/maskablepixmapwidget.cpp @@ -0,0 +1,61 @@ +/* + Copyright (C) 2014 by Project Tox + + This file is part of qTox, a Qt-based graphical interface for Tox. + + This program 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. + 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 COPYING file for more details. +*/ + +#include "maskablepixmapwidget.h" +#include +#include + +MaskablePixmapWidget::MaskablePixmapWidget(QWidget *parent, QSize size, QString maskName) + : QWidget(parent) +{ + setMinimumSize(size); + setMaximumSize(size); + + mask = QPixmap(maskName).scaled(maximumSize(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); +} + +void MaskablePixmapWidget::setPixmap(const QPixmap &pmap) +{ + pixmap = pmap.scaled(maximumSize(), Qt::KeepAspectRatio, Qt::SmoothTransformation); +} + +QPixmap MaskablePixmapWidget::getPixmap() const +{ + return pixmap; +} + +void MaskablePixmapWidget::paintEvent(QPaintEvent *ev) +{ + QPixmap tmp(ev->rect().size()); + tmp.fill(Qt::transparent); + + QPoint offset((ev->rect().size().width()-pixmap.size().width())/2,(ev->rect().size().height()-pixmap.size().height())/2); + + QPainter painter(&tmp); + painter.setCompositionMode(QPainter::CompositionMode_Source); + painter.drawPixmap(offset,pixmap); + painter.setCompositionMode(QPainter::CompositionMode_DestinationIn); + painter.drawPixmap(0,0,mask); + + painter.end(); + painter.begin(this); + painter.drawPixmap(0,0,tmp); +} + +void MaskablePixmapWidget::mousePressEvent(QMouseEvent*) +{ + emit clicked(); +} diff --git a/widget/maskablepixmapwidget.h b/widget/maskablepixmapwidget.h new file mode 100644 index 000000000..359b1ab00 --- /dev/null +++ b/widget/maskablepixmapwidget.h @@ -0,0 +1,45 @@ +/* + Copyright (C) 2014 by Project Tox + + This file is part of qTox, a Qt-based graphical interface for Tox. + + This program 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. + 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 COPYING file for more details. +*/ + +#ifndef MASKABLEPIXMAPWIDGET_H +#define MASKABLEPIXMAPWIDGET_H + +#include + +class MaskablePixmapWidget : public QWidget +{ + Q_OBJECT +public: + MaskablePixmapWidget(QWidget *parent, QSize size, QString maskName); + + void setPixmap(const QPixmap &pmap); + QPixmap getPixmap() const; + +signals: + void clicked(); + +protected: + virtual void paintEvent(QPaintEvent *ev); + virtual void mousePressEvent(QMouseEvent *); + +private: + QPixmap pixmap; + QPixmap mask; + QSize size; + QString maskName; +}; + +#endif // MASKABLEPIXMAPWIDGET_H diff --git a/widget/tool/clickablelabel.h b/widget/tool/clickablelabel.h deleted file mode 100644 index 99e523b20..000000000 --- a/widget/tool/clickablelabel.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef CLICKABLELABEL_H -#define CLICKABLELABEL_H - -#include - -class QMouseEvent; -class QWidget; - -class ClickableLabel : public QLabel -{ -Q_OBJECT - -public: - explicit ClickableLabel(QWidget* parent = 0) : QLabel(parent) {} -signals: - void clicked(); -protected: - void mousePressEvent (QMouseEvent*) {emit clicked();} -}; - - -#endif // CLICKABLELABEL_H diff --git a/widget/widget.cpp b/widget/widget.cpp index 88128d8ac..da034ace2 100644 --- a/widget/widget.cpp +++ b/widget/widget.cpp @@ -32,6 +32,7 @@ #include "camera.h" #include "widget/form/chatform.h" #include "widget/settingsdialog.h" +#include "widget/maskablepixmapwidget.h" #include #include #include @@ -111,6 +112,10 @@ Widget::Widget(QWidget *parent) isWindowMinimized = 0; + profilePicture = new MaskablePixmapWidget(this, QSize(40,40), ":/img/avatar_mask.png"); + profilePicture->setPixmap(QPixmap(":/img/avatar.png")); + ui->horizontalLayout_3->insertWidget(0,profilePicture); + ui->mainContent->setLayout(new QVBoxLayout()); ui->mainHead->setLayout(new QVBoxLayout()); ui->mainHead->layout()->setMargin(0); @@ -214,7 +219,7 @@ Widget::Widget(QWidget *parent) connect(ui->settingsButton, SIGNAL(clicked()), this, SLOT(onSettingsClicked())); connect(ui->nameLabel, SIGNAL(textChanged(QString,QString)), this, SLOT(onUsernameChanged(QString,QString))); connect(ui->statusLabel, SIGNAL(textChanged(QString,QString)), this, SLOT(onStatusMessageChanged(QString,QString))); - connect(ui->profilePicture, SIGNAL(clicked()), this, SLOT(onAvatarClicked())); + connect(profilePicture, SIGNAL(clicked()), this, SLOT(onAvatarClicked())); connect(setStatusOnline, SIGNAL(triggered()), this, SLOT(setStatusOnline())); connect(setStatusAway, SIGNAL(triggered()), this, SLOT(setStatusAway())); connect(setStatusBusy, SIGNAL(triggered()), this, SLOT(setStatusBusy())); @@ -322,8 +327,7 @@ void Widget::onAvatarClicked() void Widget::onSelfAvatarLoaded(const QPixmap& pic) { - QPixmap scaled = pic.scaled(40,40, Qt::KeepAspectRatio,Qt::SmoothTransformation); - ui->profilePicture->setPixmap(scaled); + profilePicture->setPixmap(pic); } void Widget::onConnected() diff --git a/widget/widget.h b/widget/widget.h index 352e12cfa..dd6c8180e 100644 --- a/widget/widget.h +++ b/widget/widget.h @@ -38,6 +38,7 @@ class Core; class Camera; class FriendListWidget; class SettingsDialog; +class MaskablePixmapWidget; class Widget : public QMainWindow { @@ -144,6 +145,7 @@ private: GenericChatroomWidget* activeChatroomWidget; FriendListWidget* contactListWidget; Camera* camera; + MaskablePixmapWidget* profilePicture; bool notify(QObject *receiver, QEvent *event); bool eventFilter(QObject *, QEvent *event); }; From f9df1a1503f716163597940fae470f7c35a1f7c2 Mon Sep 17 00:00:00 2001 From: krepa098 Date: Fri, 26 Sep 2014 19:16:27 +0200 Subject: [PATCH 066/205] ChatAreaWidget: removed frame --- widget/chatareawidget.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/widget/chatareawidget.cpp b/widget/chatareawidget.cpp index 524039d20..e1e7e3447 100644 --- a/widget/chatareawidget.cpp +++ b/widget/chatareawidget.cpp @@ -34,6 +34,7 @@ ChatAreaWidget::ChatAreaWidget(QWidget *parent) : setOpenExternalLinks(false); setOpenLinks(false); setAcceptRichText(false); + setFrameStyle(QFrame::NoFrame); chatTextTable = textCursor().insertTable(1,3); From d684fca868034e1a8123ef0ea7b131631e07565a Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Fri, 26 Sep 2014 21:23:20 +0200 Subject: [PATCH 067/205] Fix #322 --- core.cpp | 5 ++++- core.h | 1 + widget/form/chatform.cpp | 8 ++++++++ widget/form/chatform.h | 1 + widget/friendwidget.cpp | 9 +++++++++ widget/friendwidget.h | 1 + widget/widget.cpp | 2 ++ 7 files changed, 26 insertions(+), 1 deletion(-) diff --git a/core.cpp b/core.cpp index b2718ef5f..ebe4c4d6a 100644 --- a/core.cpp +++ b/core.cpp @@ -460,7 +460,10 @@ void Core::onAvatarInfoCallback(Tox*, int32_t friendnumber, uint8_t format, qDebug() << "Core: Got avatar info from "<(core)->tox, friendnumber); + if (format == TOX_AVATARFORMAT_NONE) + emit static_cast(core)->friendAvatarRemoved(friendnumber); + else + tox_request_avatar_data(static_cast(core)->tox, friendnumber); } void Core::onAvatarDataCallback(Tox*, int32_t friendnumber, uint8_t, diff --git a/core.h b/core.h index fb9207195..6704628b1 100644 --- a/core.h +++ b/core.h @@ -107,6 +107,7 @@ signals: void friendUsernameChanged(int friendId, const QString& username); void friendTypingChanged(int friendId, bool isTyping); void friendAvatarChanged(int friendId, const QPixmap& pic); + void friendAvatarRemoved(int friendId); void friendStatusMessageLoaded(int friendId, const QString& message); void friendUsernameLoaded(int friendId, const QString& username); diff --git a/widget/form/chatform.cpp b/widget/form/chatform.cpp index 83f9a9892..8d29c9b2d 100644 --- a/widget/form/chatform.cpp +++ b/widget/form/chatform.cpp @@ -498,3 +498,11 @@ void ChatForm::dropEvent(QDropEvent *ev) } } } + +void ChatForm::onAvatarRemoved(int FriendId) +{ + if (FriendId != f->friendId) + return; + + avatarLabel->setPixmap(QPixmap(":/img/contact_dark.png")); +} diff --git a/widget/form/chatform.h b/widget/form/chatform.h index 4604d54e3..13eba9b7d 100644 --- a/widget/form/chatform.h +++ b/widget/form/chatform.h @@ -57,6 +57,7 @@ public slots: void onAvMediaChange(int FriendId, int CallId, bool video); void onMicMuteToggle(); void onAvatarChange(int FriendId, const QPixmap& pic); + void onAvatarRemoved(int FriendId); private slots: void onSendTriggered(); diff --git a/widget/friendwidget.cpp b/widget/friendwidget.cpp index 869bc4192..b4ddc2c93 100644 --- a/widget/friendwidget.cpp +++ b/widget/friendwidget.cpp @@ -207,6 +207,15 @@ void FriendWidget::onAvatarChange(int FriendId, const QPixmap& pic) avatar.setPixmap(scaled); } +void FriendWidget::onAvatarRemoved(int FriendId) +{ + if (FriendId != friendId) + return; + + isDefaultAvatar = true; + avatar.setPixmap(QPixmap(":img/contact.png")); +} + void FriendWidget::mousePressEvent(QMouseEvent *ev) { if (ev->button() == Qt::LeftButton) diff --git a/widget/friendwidget.h b/widget/friendwidget.h index aa225d533..2f94229ee 100644 --- a/widget/friendwidget.h +++ b/widget/friendwidget.h @@ -43,6 +43,7 @@ signals: public slots: void onAvatarChange(int FriendId, const QPixmap& pic); + void onAvatarRemoved(int FriendId); protected: void mousePressEvent(QMouseEvent* ev); diff --git a/widget/widget.cpp b/widget/widget.cpp index 88128d8ac..3f3137717 100644 --- a/widget/widget.cpp +++ b/widget/widget.cpp @@ -468,6 +468,8 @@ void Widget::addFriend(int friendId, const QString &userId) connect(core, &Core::avMediaChange, newfriend->chatForm, &ChatForm::onAvMediaChange); connect(core, &Core::friendAvatarChanged, newfriend->chatForm, &ChatForm::onAvatarChange); connect(core, &Core::friendAvatarChanged, newfriend->widget, &FriendWidget::onAvatarChange); + connect(core, &Core::friendAvatarRemoved, newfriend->chatForm, &ChatForm::onAvatarRemoved); + connect(core, &Core::friendAvatarRemoved, newfriend->widget, &FriendWidget::onAvatarRemoved); // Try to get the avatar from the cache QPixmap avatar = Settings::getInstance().getSavedAvatar(userId); From 0f7cb138258f4b236bfa5051bb30e8cb98835cad Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Fri, 26 Sep 2014 21:56:51 +0200 Subject: [PATCH 068/205] Typo when fixing #322 --- core.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core.cpp b/core.cpp index ebe4c4d6a..5e96e1a29 100644 --- a/core.cpp +++ b/core.cpp @@ -460,7 +460,7 @@ void Core::onAvatarInfoCallback(Tox*, int32_t friendnumber, uint8_t format, qDebug() << "Core: Got avatar info from "<(core)->friendAvatarRemoved(friendnumber); else tox_request_avatar_data(static_cast(core)->tox, friendnumber); From aff0f915d0ea6df1608f785da9476c81c88de7ca Mon Sep 17 00:00:00 2001 From: dubslow Date: Fri, 26 Sep 2014 17:04:01 -0500 Subject: [PATCH 069/205] incomplete os x instructions --- INSTALL.md | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/INSTALL.md b/INSTALL.md index b5b2d5f11..9f4738b12 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -69,7 +69,7 @@ make install Copy the dll "OpenAL32.dll" located at "C:\qTox\libs\openal-build\install\bin" to "C:\qTox\libs\lib". Finally, copy the directory "AL" located at "C:\qTox\libs\openal-build\install\include" to "C:\qTox\libs\include". Unlike OpenCV you don't need to patch any files. Feel free to delete the directories "openal-soft-x.y.z" and "openal-build", but you don't need to. ##Linux -Most of the dependencies should be available through your package manger. +Most of the dependencies should be available through your package manger. You may either follow the directions below, or simply run `./simple_make.sh` which will attempt to automatically download dependencies. ###Cloning the Repository In order to clone the qTox repository you need Git. @@ -164,3 +164,59 @@ form natively, and .rpm form with alien< After installing the required dependencies, run `bootstrap.sh` and then run the `buildPackages.sh` script, found in the tools folder. It will automatically get the packages necessary for building .debs, so be prepared to type your password for sudo. + +##OS X + +###OSX Easy Install + +Since https://github.com/ReDetection/homebrew-qtox you can easily install qtox with homebrew +```bash +brew install --HEAD ReDetection/qtox/qtox +``` + +###OSX Full Install Guide + +This guide is intended for people who wish to use an existing or new ProjectTox-Core installation separate to the bundled installation with qTox, if you do not wish to use a separate installation you can skip to the section titled 'Final Steps'. + +Installation on OSX, isn't quite straight forward, here is a quick guide on how to install; + +The first thing you need to do is install ProjectTox-Core with a/v support. Refer to the INSTALL guide in the PrjectTox-Core github repo. + +Next you need to download QtTools (http://qt-project.org/downloads), at the time of writing this is at version .3.0. +Make sure you deselect all the unnecessary components from the 5.3 checkbox (iOS/Android libs) otherwise you will end up with a very large download. + +Once that is installed you will most likely need to set the path for qmake. To do this, open up terminal and paste in the following; + +```bash +export PATH=/location/to/qmake/binary:$PATH +``` + +For myself, the qmake binary was located in /Users/mouseym/Qt/5.3/clang_64/bin/. + +This is not a permanent change, it will revert when you close the terminal window, to add it permanently you will need to add echo the above line to your .profile/.bash_profile. + +Once this is installed, do the following; + +```bash +git clone https://github.com/tux3/qTox +cd toxgui +qmake +``` + +Now, we need to create a symlink to /usr/local/lib/ and /usr/local/include/ +``` +mkdir -p $HOME/qTox/libs +sudo ln -s /usr/local/lib $HOME/qTox/libs/lib +sudo ln -s /usr/local/include $HOME/qTox/libs/include +``` +####Final Steps + +The final step is to run +```bash +make +``` +in the qTox directory, or if you are using the bundled tox core installation, you can use +```bash +./bootstrap.sh +``` +Assuming all went well you should now have a qTox.app file within the directory. Double click and it should open! From 8bc439decc4f9833fbaad47f56fd61865b1cebfd Mon Sep 17 00:00:00 2001 From: dubslow Date: Fri, 26 Sep 2014 17:06:33 -0500 Subject: [PATCH 070/205] minor fixes --- INSTALL.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/INSTALL.md b/INSTALL.md index 9f4738b12..74fdc2683 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -156,7 +156,7 @@ cd /home/user/qTox ./bootstrap.sh # use -h or --help for more information ``` -##Building packages +###Building packages qTox now has the experimental and probably-dodgy ability to package itself (in .deb form natively, and .rpm form with alien). @@ -180,6 +180,8 @@ This guide is intended for people who wish to use an existing or new ProjectTox- Installation on OSX, isn't quite straight forward, here is a quick guide on how to install; +Note that qTox now requires OpenCV and OpenAL for audio and video. + The first thing you need to do is install ProjectTox-Core with a/v support. Refer to the INSTALL guide in the PrjectTox-Core github repo. Next you need to download QtTools (http://qt-project.org/downloads), at the time of writing this is at version .3.0. From 25b2c76f4bdcec67deec576272520e877b6672b2 Mon Sep 17 00:00:00 2001 From: dubslow Date: Fri, 26 Sep 2014 17:11:13 -0500 Subject: [PATCH 071/205] minor fixes --- INSTALL.md | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/INSTALL.md b/INSTALL.md index 74fdc2683..3cb777597 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -69,7 +69,7 @@ make install Copy the dll "OpenAL32.dll" located at "C:\qTox\libs\openal-build\install\bin" to "C:\qTox\libs\lib". Finally, copy the directory "AL" located at "C:\qTox\libs\openal-build\install\include" to "C:\qTox\libs\include". Unlike OpenCV you don't need to patch any files. Feel free to delete the directories "openal-soft-x.y.z" and "openal-build", but you don't need to. ##Linux -Most of the dependencies should be available through your package manger. You may either follow the directions below, or simply run `./simple_make.sh` which will attempt to automatically download dependencies. +Most of the dependencies should be available through your package manger. You may either follow the directions below, or simply run `./simple_make.sh` after cloning, which will attempt to automatically download dependencies followed by compilation. ###Cloning the Repository In order to clone the qTox repository you need Git. @@ -156,9 +156,15 @@ cd /home/user/qTox ./bootstrap.sh # use -h or --help for more information ``` +After all the dependencies are thus reeady to go, compiling should be as simple as +```bash +qmake +make +``` + ###Building packages -qTox now has the experimental and probably-dodgy ability to package itself (in .deb +Alternately, qTox now has the experimental and probably-dodgy ability to package itself (in .deb form natively, and .rpm form with alien). After installing the required dependencies, run `bootstrap.sh` and then run the @@ -180,7 +186,7 @@ This guide is intended for people who wish to use an existing or new ProjectTox- Installation on OSX, isn't quite straight forward, here is a quick guide on how to install; -Note that qTox now requires OpenCV and OpenAL for audio and video. +Note that qTox now requires OpenCV and OpenAL for video and audio. The first thing you need to do is install ProjectTox-Core with a/v support. Refer to the INSTALL guide in the PrjectTox-Core github repo. @@ -220,5 +226,6 @@ make in the qTox directory, or if you are using the bundled tox core installation, you can use ```bash ./bootstrap.sh +make ``` Assuming all went well you should now have a qTox.app file within the directory. Double click and it should open! From 4d24bd53f26133a0fc4a7ffb68031eb92bca1ede Mon Sep 17 00:00:00 2001 From: krepa098 Date: Sat, 27 Sep 2014 13:23:00 +0200 Subject: [PATCH 072/205] fix #308 --- widget/chatareawidget.cpp | 2 +- widget/tool/chatactions/chataction.h | 3 ++- .../tool/chatactions/filetransferaction.cpp | 21 +++++++++++++++---- widget/tool/chatactions/filetransferaction.h | 3 ++- widget/tool/chatactions/messageaction.cpp | 2 +- widget/tool/chatactions/messageaction.h | 2 +- .../tool/chatactions/systemmessageaction.cpp | 2 +- widget/tool/chatactions/systemmessageaction.h | 2 +- 8 files changed, 26 insertions(+), 11 deletions(-) diff --git a/widget/chatareawidget.cpp b/widget/chatareawidget.cpp index e1e7e3447..765d9e96c 100644 --- a/widget/chatareawidget.cpp +++ b/widget/chatareawidget.cpp @@ -118,7 +118,7 @@ void ChatAreaWidget::insertMessage(ChatAction *msgAction) chatTextTable->cellAt(row,1).firstCursorPosition().insertHtml(msgAction->getMessage()); chatTextTable->cellAt(row,2).firstCursorPosition().insertText(msgAction->getDate()); - msgAction->setTextCursor(cur); + msgAction->setup(cur, this); messages.append(msgAction); } diff --git a/widget/tool/chatactions/chataction.h b/widget/tool/chatactions/chataction.h index 16c9f179b..5c3eed650 100644 --- a/widget/tool/chatactions/chataction.h +++ b/widget/tool/chatactions/chataction.h @@ -21,13 +21,14 @@ #include class FileTransferInstance; +class QTextEdit; class ChatAction : public QObject { public: ChatAction(const bool &me, const QString &author, const QString &date) : isMe(me), name(author), date(date) {;} virtual ~ChatAction(){;} - virtual void setTextCursor(QTextCursor cursor){(void)cursor;} ///< Call once, and then you MUST let the object update itself + virtual void setup(QTextCursor cursor, QTextEdit* textEdit) = 0; ///< Call once, and then you MUST let the object update itself virtual QString getName(); virtual QString getMessage() = 0; diff --git a/widget/tool/chatactions/filetransferaction.cpp b/widget/tool/chatactions/filetransferaction.cpp index 12e2a1ac6..59f2c9250 100644 --- a/widget/tool/chatactions/filetransferaction.cpp +++ b/widget/tool/chatactions/filetransferaction.cpp @@ -17,8 +17,12 @@ #include "filetransferaction.h" #include "filetransferinstance.h" -FileTransferAction::FileTransferAction(FileTransferInstance *widget, const QString &author, const QString &date, const bool &me) : - ChatAction(me, author, date) +#include +#include + +FileTransferAction::FileTransferAction(FileTransferInstance *widget, const QString &author, const QString &date, const bool &me) + : ChatAction(me, author, date) + , edit(nullptr) { w = widget; @@ -39,20 +43,26 @@ QString FileTransferAction::getMessage() return widgetHtml; } -void FileTransferAction::setTextCursor(QTextCursor cursor) +void FileTransferAction::setup(QTextCursor cursor, QTextEdit *textEdit) { cur = cursor; cur.setKeepPositionOnInsert(true); int end=cur.selectionEnd(); cur.setPosition(cur.position()); cur.setPosition(end, QTextCursor::KeepAnchor); + + edit = textEdit; } void FileTransferAction::updateHtml() { - if (cur.isNull()) + if (cur.isNull() || !edit) return; + // save old slider value + int vSliderVal = edit->verticalScrollBar()->value(); + + // update content int pos = cur.selectionStart(); cur.removeSelectedText(); cur.setKeepPositionOnInsert(false); @@ -62,6 +72,9 @@ void FileTransferAction::updateHtml() cur.setPosition(pos); cur.setPosition(end, QTextCursor::KeepAnchor); + // restore old slider value + edit->verticalScrollBar()->setValue(vSliderVal); + // Free our ressources if we'll never need to update again if (w->getState() == FileTransferInstance::TransfState::tsCanceled || w->getState() == FileTransferInstance::TransfState::tsFinished) diff --git a/widget/tool/chatactions/filetransferaction.h b/widget/tool/chatactions/filetransferaction.h index ee6d0e11c..31982cd45 100644 --- a/widget/tool/chatactions/filetransferaction.h +++ b/widget/tool/chatactions/filetransferaction.h @@ -26,7 +26,7 @@ public: FileTransferAction(FileTransferInstance *widget, const QString &author, const QString &date, const bool &me); virtual ~FileTransferAction(); virtual QString getMessage(); - virtual void setTextCursor(QTextCursor cursor) final; + virtual void setup(QTextCursor cursor, QTextEdit* textEdit) override; private slots: void updateHtml(); @@ -34,6 +34,7 @@ private slots: private: FileTransferInstance *w; QTextCursor cur; + QTextEdit* edit; }; #endif // FILETRANSFERACTION_H diff --git a/widget/tool/chatactions/messageaction.cpp b/widget/tool/chatactions/messageaction.cpp index fa396468c..84ce86194 100644 --- a/widget/tool/chatactions/messageaction.cpp +++ b/widget/tool/chatactions/messageaction.cpp @@ -23,7 +23,7 @@ MessageAction::MessageAction(const QString &author, const QString &message, cons { } -void MessageAction::setTextCursor(QTextCursor cursor) +void MessageAction::setup(QTextCursor cursor, QTextEdit *) { // When this function is called, we're supposed to only update ourselve when needed // Nobody should ask us to do anything with our content, we're on our own diff --git a/widget/tool/chatactions/messageaction.h b/widget/tool/chatactions/messageaction.h index baa68898a..65f8e6465 100644 --- a/widget/tool/chatactions/messageaction.h +++ b/widget/tool/chatactions/messageaction.h @@ -25,7 +25,7 @@ public: MessageAction(const QString &author, const QString &message, const QString &date, const bool &me); virtual ~MessageAction(){;} virtual QString getMessage(); - virtual void setTextCursor(QTextCursor cursor) final; + virtual void setup(QTextCursor cursor, QTextEdit*) override; private: QString message; diff --git a/widget/tool/chatactions/systemmessageaction.cpp b/widget/tool/chatactions/systemmessageaction.cpp index 32457c6ed..a50f55e47 100644 --- a/widget/tool/chatactions/systemmessageaction.cpp +++ b/widget/tool/chatactions/systemmessageaction.cpp @@ -28,7 +28,7 @@ QString SystemMessageAction::getMessage() return QString("
" + message + "
"); } -void SystemMessageAction::setTextCursor(QTextCursor cursor) +void SystemMessageAction::setup(QTextCursor cursor, QTextEdit *) { // When this function is called, we're supposed to only update ourselve when needed // Nobody should ask us to do anything with our content, we're on our own diff --git a/widget/tool/chatactions/systemmessageaction.h b/widget/tool/chatactions/systemmessageaction.h index b628f7e04..6767a3f73 100644 --- a/widget/tool/chatactions/systemmessageaction.h +++ b/widget/tool/chatactions/systemmessageaction.h @@ -24,7 +24,7 @@ class SystemMessageAction : public ChatAction public: SystemMessageAction(const QString &message, const QString& type, const QString &date); virtual ~SystemMessageAction(){;} - virtual void setTextCursor(QTextCursor cursor) final; + virtual void setup(QTextCursor cursor, QTextEdit*) override; virtual QString getName() {return QString();} virtual QString getMessage(); From cd0f8d4d58116b76bca7045be07a6191f9dc7be6 Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Sat, 27 Sep 2014 14:37:51 +0200 Subject: [PATCH 073/205] Fix #326 From faf59cea9c72fa1774a3587029f51e9e6acd9e96 Mon Sep 17 00:00:00 2001 From: Joni Martikainen Date: Sun, 21 Sep 2014 23:33:07 +0300 Subject: [PATCH 074/205] check if call is active before mute check if call is active before mute. Prevents segfault. --- coreav.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/coreav.cpp b/coreav.cpp index 9244fe433..fa4ce5cd8 100644 --- a/coreav.cpp +++ b/coreav.cpp @@ -273,7 +273,9 @@ void Core::decreaseVideoBusyness() void Core::micMuteToggle(int callId) { - calls[callId].muteMic = !calls[callId].muteMic; + if (calls[callId].active) { + calls[callId].muteMic = !calls[callId].muteMic; + } } void Core::onAvCancel(void* _toxav, int32_t callId, void* core) From 97b5599651f7dd469f4f7dcf8b1fe4e50cf6e381 Mon Sep 17 00:00:00 2001 From: krepa098 Date: Sat, 27 Sep 2014 15:39:17 +0200 Subject: [PATCH 075/205] MaskablePixmapWidget: fixed drawing routine --- widget/maskablepixmapwidget.cpp | 17 +++++++---------- widget/maskablepixmapwidget.h | 2 +- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/widget/maskablepixmapwidget.cpp b/widget/maskablepixmapwidget.cpp index 6fdd3f03b..0959a5a20 100644 --- a/widget/maskablepixmapwidget.cpp +++ b/widget/maskablepixmapwidget.cpp @@ -16,20 +16,17 @@ #include "maskablepixmapwidget.h" #include -#include MaskablePixmapWidget::MaskablePixmapWidget(QWidget *parent, QSize size, QString maskName) : QWidget(parent) { - setMinimumSize(size); - setMaximumSize(size); - - mask = QPixmap(maskName).scaled(maximumSize(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + setFixedSize(size); + mask = QPixmap(maskName).scaled(size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); } void MaskablePixmapWidget::setPixmap(const QPixmap &pmap) { - pixmap = pmap.scaled(maximumSize(), Qt::KeepAspectRatio, Qt::SmoothTransformation); + pixmap = pmap.scaled(width(), height(), Qt::KeepAspectRatio, Qt::SmoothTransformation); } QPixmap MaskablePixmapWidget::getPixmap() const @@ -37,20 +34,20 @@ QPixmap MaskablePixmapWidget::getPixmap() const return pixmap; } -void MaskablePixmapWidget::paintEvent(QPaintEvent *ev) +void MaskablePixmapWidget::paintEvent(QPaintEvent *) { - QPixmap tmp(ev->rect().size()); + QPixmap tmp(width(), height()); tmp.fill(Qt::transparent); - QPoint offset((ev->rect().size().width()-pixmap.size().width())/2,(ev->rect().size().height()-pixmap.size().height())/2); + QPoint offset((width() - pixmap.size().width())/2,(height() - pixmap.size().height())/2); // centering the pixmap QPainter painter(&tmp); painter.setCompositionMode(QPainter::CompositionMode_Source); painter.drawPixmap(offset,pixmap); painter.setCompositionMode(QPainter::CompositionMode_DestinationIn); painter.drawPixmap(0,0,mask); - painter.end(); + painter.begin(this); painter.drawPixmap(0,0,tmp); } diff --git a/widget/maskablepixmapwidget.h b/widget/maskablepixmapwidget.h index 359b1ab00..faaf4abf3 100644 --- a/widget/maskablepixmapwidget.h +++ b/widget/maskablepixmapwidget.h @@ -32,7 +32,7 @@ signals: void clicked(); protected: - virtual void paintEvent(QPaintEvent *ev); + virtual void paintEvent(QPaintEvent *); virtual void mousePressEvent(QMouseEvent *); private: From de7ade033a0eb60a0913f477062588837b60ac40 Mon Sep 17 00:00:00 2001 From: krepa098 Date: Sat, 27 Sep 2014 16:37:16 +0200 Subject: [PATCH 076/205] MaskablePixmapWidget: white background, removed circular mask --- img/avatar_mask.png | Bin 5766 -> 3602 bytes img/avatar_mask_circle.png | Bin 9310 -> 0 bytes widget/form/genericchatform.cpp | 2 +- widget/maskablepixmapwidget.cpp | 3 ++- 4 files changed, 3 insertions(+), 2 deletions(-) delete mode 100644 img/avatar_mask_circle.png diff --git a/img/avatar_mask.png b/img/avatar_mask.png index 508914f0425838a3c1b5496ff87ff6388115ace3..2527e336522e8c2014d399ee1e277b2ce3bc9cf1 100644 GIT binary patch literal 3602 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 gWr(=7(0;p!HfY`X17htZas?mKQK?1qW}N^ diff --git a/img/avatar_mask_circle.png b/img/avatar_mask_circle.png deleted file mode 100644 index 83cb97dfc4e3874237965d1d0a961bd1cbb91592..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9310 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 diff --git a/widget/form/genericchatform.cpp b/widget/form/genericchatform.cpp index 1f7b827f7..a10fe0c83 100644 --- a/widget/form/genericchatform.cpp +++ b/widget/form/genericchatform.cpp @@ -36,7 +36,7 @@ GenericChatForm::GenericChatForm(QWidget *parent) : headWidget = new QWidget(); nameLabel = new CroppingLabel(); - avatar = new MaskablePixmapWidget(this, QSize(40,40), ":/img/avatar_mask_circle.png"); + avatar = new MaskablePixmapWidget(this, QSize(40,40), ":/img/avatar_mask.png"); QHBoxLayout *headLayout = new QHBoxLayout(), *mainFootLayout = new QHBoxLayout(); headTextLayout = new QVBoxLayout(); QVBoxLayout *mainLayout = new QVBoxLayout(); diff --git a/widget/maskablepixmapwidget.cpp b/widget/maskablepixmapwidget.cpp index 0959a5a20..cdbe5c9b9 100644 --- a/widget/maskablepixmapwidget.cpp +++ b/widget/maskablepixmapwidget.cpp @@ -42,7 +42,8 @@ void MaskablePixmapWidget::paintEvent(QPaintEvent *) QPoint offset((width() - pixmap.size().width())/2,(height() - pixmap.size().height())/2); // centering the pixmap QPainter painter(&tmp); - painter.setCompositionMode(QPainter::CompositionMode_Source); + painter.setCompositionMode(QPainter::CompositionMode_SourceOver); + painter.fillRect(0,0,width(),height(),Qt::white); painter.drawPixmap(offset,pixmap); painter.setCompositionMode(QPainter::CompositionMode_DestinationIn); painter.drawPixmap(0,0,mask); From a245255550fb8a331378f9b595a8dbb80b733278 Mon Sep 17 00:00:00 2001 From: krepa098 Date: Sat, 27 Sep 2014 16:39:54 +0200 Subject: [PATCH 077/205] removed avatar_mask_circle.png from qrc --- res.qrc | 1 - 1 file changed, 1 deletion(-) diff --git a/res.qrc b/res.qrc index 62b891ee6..603fc8ba2 100644 --- a/res.qrc +++ b/res.qrc @@ -143,6 +143,5 @@ translations/fi.qm translations/mannol.qm img/avatar_mask.png - img/avatar_mask_circle.png From 329f57d33a0251df1f95c0ddf356adab55ac5478 Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Sat, 27 Sep 2014 17:01:31 +0200 Subject: [PATCH 078/205] debian: Shouldn't depend on metapackages --- debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/control b/debian/control index ef73726b7..7883115e6 100644 --- a/debian/control +++ b/debian/control @@ -3,7 +3,7 @@ Maintainer: John Smith Section: misc Priority: optional Standards-Version: 3.9.5 -Build-Depends: debhelper (>= 9), cdbs, qt5-qmake, qt5-default, libopenal-dev, libopencv-dev, libopus-dev +Build-Depends: debhelper (>= 9), cdbs, qt5-qmake, libopenal-dev, libopencv-dev, libopus-dev Package: qtox Architecture: any From 5411db5bec5b5899c2da4d19f7ddb9a189aca58c Mon Sep 17 00:00:00 2001 From: krepa098 Date: Sat, 27 Sep 2014 17:41:17 +0200 Subject: [PATCH 079/205] MaskablePixmapWidget: background-color argument --- widget/maskablepixmapwidget.cpp | 5 +++-- widget/maskablepixmapwidget.h | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/widget/maskablepixmapwidget.cpp b/widget/maskablepixmapwidget.cpp index cdbe5c9b9..9257416fc 100644 --- a/widget/maskablepixmapwidget.cpp +++ b/widget/maskablepixmapwidget.cpp @@ -17,8 +17,9 @@ #include "maskablepixmapwidget.h" #include -MaskablePixmapWidget::MaskablePixmapWidget(QWidget *parent, QSize size, QString maskName) +MaskablePixmapWidget::MaskablePixmapWidget(QWidget *parent, QSize size, QString maskName, QColor background) : QWidget(parent) + , backgroundColor(background) { setFixedSize(size); mask = QPixmap(maskName).scaled(size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); @@ -43,7 +44,7 @@ void MaskablePixmapWidget::paintEvent(QPaintEvent *) QPainter painter(&tmp); painter.setCompositionMode(QPainter::CompositionMode_SourceOver); - painter.fillRect(0,0,width(),height(),Qt::white); + painter.fillRect(0,0,width(),height(),backgroundColor); painter.drawPixmap(offset,pixmap); painter.setCompositionMode(QPainter::CompositionMode_DestinationIn); painter.drawPixmap(0,0,mask); diff --git a/widget/maskablepixmapwidget.h b/widget/maskablepixmapwidget.h index faaf4abf3..72ae39b42 100644 --- a/widget/maskablepixmapwidget.h +++ b/widget/maskablepixmapwidget.h @@ -23,7 +23,7 @@ class MaskablePixmapWidget : public QWidget { Q_OBJECT public: - MaskablePixmapWidget(QWidget *parent, QSize size, QString maskName); + MaskablePixmapWidget(QWidget *parent, QSize size, QString maskName, QColor background = Qt::white); void setPixmap(const QPixmap &pmap); QPixmap getPixmap() const; @@ -40,6 +40,7 @@ private: QPixmap mask; QSize size; QString maskName; + QColor backgroundColor; }; #endif // MASKABLEPIXMAPWIDGET_H From 76e5876f0ae9c735db8c49b15039a61286be15da Mon Sep 17 00:00:00 2001 From: krepa098 Date: Sat, 27 Sep 2014 17:45:38 +0200 Subject: [PATCH 080/205] set default avatar to contact_dark.png, removed active/inactive avatar switching --- widget/friendwidget.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/widget/friendwidget.cpp b/widget/friendwidget.cpp index c15ee03cc..6cea7ad03 100644 --- a/widget/friendwidget.cpp +++ b/widget/friendwidget.cpp @@ -45,7 +45,7 @@ FriendWidget::FriendWidget(int FriendId, QString id) setLayoutDirection(Qt::LeftToRight); // parent might have set Qt::RightToLeft avatar = new MaskablePixmapWidget(this, QSize(40,40), ":/img/avatar_mask.png"); - avatar->setPixmap(QPixmap(":img/contact.png")); + avatar->setPixmap(QPixmap(":img/contact_dark.png")); name.setText(id); //statusPic.setAlignment(Qt::AlignHCenter); statusPic.setPixmap(QPixmap(":img/status/dot_away.png")); @@ -140,8 +140,6 @@ void FriendWidget::setAsActiveChatroom() QPalette pal3; pal3.setColor(QPalette::Background, Qt::white); this->setPalette(pal3); - if (isDefaultAvatar) - avatar->setPixmap(QPixmap(":img/contact_dark.png")); } void FriendWidget::setAsInactiveChatroom() @@ -160,9 +158,6 @@ void FriendWidget::setAsInactiveChatroom() QPalette pal3; pal3.setColor(QPalette::Background, QColor(65,65,65,255)); this->setPalette(pal3); - - if (isDefaultAvatar) - avatar->setPixmap(QPixmap(":img/contact.png")); } void FriendWidget::updateStatusLight() From bb214b53f7aa97069fd3c245b72f7a811978ff9f Mon Sep 17 00:00:00 2001 From: krepa098 Date: Sat, 27 Sep 2014 17:58:56 +0200 Subject: [PATCH 081/205] set profile picture to contact_dark.png --- widget/widget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/widget/widget.cpp b/widget/widget.cpp index da034ace2..8057c221f 100644 --- a/widget/widget.cpp +++ b/widget/widget.cpp @@ -113,7 +113,7 @@ Widget::Widget(QWidget *parent) isWindowMinimized = 0; profilePicture = new MaskablePixmapWidget(this, QSize(40,40), ":/img/avatar_mask.png"); - profilePicture->setPixmap(QPixmap(":/img/avatar.png")); + profilePicture->setPixmap(QPixmap(":/img/contact_dark.png")); ui->horizontalLayout_3->insertWidget(0,profilePicture); ui->mainContent->setLayout(new QVBoxLayout()); From 18330f0928a07d01740cbc2fd76896d30afd0932 Mon Sep 17 00:00:00 2001 From: krepa098 Date: Sat, 27 Sep 2014 18:00:13 +0200 Subject: [PATCH 082/205] MaskablePixmapWidget: set cursor to PointingHandCursor if clickable --- widget/maskablepixmapwidget.cpp | 14 +++++++++++++- widget/maskablepixmapwidget.h | 2 ++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/widget/maskablepixmapwidget.cpp b/widget/maskablepixmapwidget.cpp index 9257416fc..bc47f1154 100644 --- a/widget/maskablepixmapwidget.cpp +++ b/widget/maskablepixmapwidget.cpp @@ -20,11 +20,22 @@ MaskablePixmapWidget::MaskablePixmapWidget(QWidget *parent, QSize size, QString maskName, QColor background) : QWidget(parent) , backgroundColor(background) + , clickable(false) { setFixedSize(size); mask = QPixmap(maskName).scaled(size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); } +void MaskablePixmapWidget::setClickable(bool clickable) +{ + this->clickable = clickable; + + if (clickable) + setCursor(Qt::PointingHandCursor); + else + unsetCursor(); +} + void MaskablePixmapWidget::setPixmap(const QPixmap &pmap) { pixmap = pmap.scaled(width(), height(), Qt::KeepAspectRatio, Qt::SmoothTransformation); @@ -56,5 +67,6 @@ void MaskablePixmapWidget::paintEvent(QPaintEvent *) void MaskablePixmapWidget::mousePressEvent(QMouseEvent*) { - emit clicked(); + if(clickable) + emit clicked(); } diff --git a/widget/maskablepixmapwidget.h b/widget/maskablepixmapwidget.h index 72ae39b42..c4601d227 100644 --- a/widget/maskablepixmapwidget.h +++ b/widget/maskablepixmapwidget.h @@ -25,6 +25,7 @@ class MaskablePixmapWidget : public QWidget public: MaskablePixmapWidget(QWidget *parent, QSize size, QString maskName, QColor background = Qt::white); + void setClickable(bool clickable); void setPixmap(const QPixmap &pmap); QPixmap getPixmap() const; @@ -41,6 +42,7 @@ private: QSize size; QString maskName; QColor backgroundColor; + bool clickable; }; #endif // MASKABLEPIXMAPWIDGET_H From 2b58d45b73920808ce0843edd8aef42c8e5599ef Mon Sep 17 00:00:00 2001 From: krepa098 Date: Sat, 27 Sep 2014 19:13:27 +0200 Subject: [PATCH 083/205] MaskablePixmapWidget: use KeepAspectRatioByExpanding --- widget/maskablepixmapwidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/widget/maskablepixmapwidget.cpp b/widget/maskablepixmapwidget.cpp index bc47f1154..305eb015c 100644 --- a/widget/maskablepixmapwidget.cpp +++ b/widget/maskablepixmapwidget.cpp @@ -38,7 +38,7 @@ void MaskablePixmapWidget::setClickable(bool clickable) void MaskablePixmapWidget::setPixmap(const QPixmap &pmap) { - pixmap = pmap.scaled(width(), height(), Qt::KeepAspectRatio, Qt::SmoothTransformation); + pixmap = pmap.scaled(width(), height(), Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation); } QPixmap MaskablePixmapWidget::getPixmap() const From 9b52d3174d69b2794d9a8ec322881bb27df185fc Mon Sep 17 00:00:00 2001 From: krepa098 Date: Sat, 27 Sep 2014 19:13:46 +0200 Subject: [PATCH 084/205] set clickable to true --- widget/widget.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/widget/widget.cpp b/widget/widget.cpp index 8057c221f..22f65aa74 100644 --- a/widget/widget.cpp +++ b/widget/widget.cpp @@ -114,6 +114,7 @@ Widget::Widget(QWidget *parent) profilePicture = new MaskablePixmapWidget(this, QSize(40,40), ":/img/avatar_mask.png"); profilePicture->setPixmap(QPixmap(":/img/contact_dark.png")); + profilePicture->setClickable(true); ui->horizontalLayout_3->insertWidget(0,profilePicture); ui->mainContent->setLayout(new QVBoxLayout()); From 63252d2fc0984b16aeee42fa54a3af26e61c1389 Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Sat, 27 Sep 2014 20:21:56 +0200 Subject: [PATCH 085/205] Fix merge --- widget/form/chatform.cpp | 2 +- widget/friendwidget.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/widget/form/chatform.cpp b/widget/form/chatform.cpp index dc8b7bf05..a200eff08 100644 --- a/widget/form/chatform.cpp +++ b/widget/form/chatform.cpp @@ -505,5 +505,5 @@ void ChatForm::onAvatarRemoved(int FriendId) if (FriendId != f->friendId) return; - avatarLabel->setPixmap(QPixmap(":/img/contact_dark.png")); + avatar->setPixmap(QPixmap(":/img/contact_dark.png")); } diff --git a/widget/friendwidget.cpp b/widget/friendwidget.cpp index 7b09c2b95..5bce871f7 100644 --- a/widget/friendwidget.cpp +++ b/widget/friendwidget.cpp @@ -210,7 +210,7 @@ void FriendWidget::onAvatarRemoved(int FriendId) return; isDefaultAvatar = true; - avatar.setPixmap(QPixmap(":img/contact.png")); + avatar->setPixmap(QPixmap(":img/contact.png")); } void FriendWidget::mousePressEvent(QMouseEvent *ev) From f6176e4a3cb522679a40fff790e6ef30da98f35f Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Sat, 27 Sep 2014 21:07:13 +0200 Subject: [PATCH 086/205] buildPackages.sh shouldn't be interactive --- tools/buildPackages.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/buildPackages.sh b/tools/buildPackages.sh index dc01f4a82..80117b281 100755 --- a/tools/buildPackages.sh +++ b/tools/buildPackages.sh @@ -56,9 +56,9 @@ done if [[ $OPT_APT = "true" ]]; then echo "Installing missing tools (if any)..." if [[ $EUID -ne 0 && $OPT_SUDO = "true" ]]; then - sudo apt-get install wget debhelper cdbs devscripts alien tar gzip build-essential + sudo apt-get install wget debhelper cdbs devscripts alien tar gzip build-essential -y else - apt-get install wget debhelper cdbs devscripts alien tar gzip build-essential + apt-get install wget debhelper cdbs devscripts alien tar gzip build-essential -y fi fi From 702daa987b2eb252706d840cd6cda0406f03bb9e Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Sat, 27 Sep 2014 21:25:42 +0200 Subject: [PATCH 087/205] Make buildPackages.sh install dependencies --- tools/buildPackages.sh | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tools/buildPackages.sh b/tools/buildPackages.sh index 80117b281..e028670e5 100755 --- a/tools/buildPackages.sh +++ b/tools/buildPackages.sh @@ -62,6 +62,16 @@ if [[ $OPT_APT = "true" ]]; then fi fi +# Get the requried dependencies if needed +if [[ $OPT_APT = "true" ]]; then + echo "Installing missing dependencies (if any)..." + if [[ $EUID -ne 0 && $OPT_SUDO = "true" ]]; then + sudo apt-get install qt5-qmake libopenal-dev libopencv-dev libopus-dev -y + else + apt-get install qt5-qmake libopenal-dev libopencv-dev libopus-dev -y + fi +fi + mkdir -p .packages cd .packages From db1413387564f78eabc0f03f5fc80962263ef537 Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Sat, 27 Sep 2014 23:26:43 +0200 Subject: [PATCH 088/205] update debian packages --- debian/control | 2 +- debian/rules | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/control b/debian/control index 7883115e6..093a912a2 100644 --- a/debian/control +++ b/debian/control @@ -3,7 +3,7 @@ Maintainer: John Smith Section: misc Priority: optional Standards-Version: 3.9.5 -Build-Depends: debhelper (>= 9), cdbs, qt5-qmake, libopenal-dev, libopencv-dev, libopus-dev +Build-Depends: debhelper (>= 9), cdbs, qt5-qmake, libopenal-dev, libopencv-dev, libopus-dev, qtbase5-dev Package: qtox Architecture: any diff --git a/debian/rules b/debian/rules index 6815966a4..6222f176d 100644 --- a/debian/rules +++ b/debian/rules @@ -3,4 +3,4 @@ include /usr/share/cdbs/1/rules/debhelper.mk include /usr/share/cdbs/1/class/qmake.mk -QMAKE=qmake STATICPKG=YES +QMAKE=qmake STATICPKG=YES -qt=5 From 547181ec48ea766663d21a9de03af0143622dcbc Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Sat, 27 Sep 2014 23:31:34 +0200 Subject: [PATCH 089/205] update debian packages --- debian/rules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/rules b/debian/rules index 6222f176d..5d17ec7e7 100644 --- a/debian/rules +++ b/debian/rules @@ -3,4 +3,4 @@ include /usr/share/cdbs/1/rules/debhelper.mk include /usr/share/cdbs/1/class/qmake.mk -QMAKE=qmake STATICPKG=YES -qt=5 +QMAKE=qmake -qt=5 STATICPKG=YES From 28d2680fec53bfd162999e003f2fa069221ea3b8 Mon Sep 17 00:00:00 2001 From: dubslow Date: Sat, 27 Sep 2014 16:37:39 -0500 Subject: [PATCH 090/205] conform to standard, fix bug related to nospam in ID --- core.cpp | 36 ++++++++++++++++++++++++------------ settings.cpp | 19 +++++++++++++++---- settings.h | 1 - widget/widget.cpp | 2 +- 4 files changed, 40 insertions(+), 18 deletions(-) diff --git a/core.cpp b/core.cpp index 5e96e1a29..32f614721 100644 --- a/core.cpp +++ b/core.cpp @@ -210,7 +210,8 @@ void Core::start() tox_get_address(tox, friendAddress); emit friendAddressGenerated(CFriendAddress::toString(friendAddress)); - QPixmap pic = Settings::getInstance().getSavedAvatar(getSelfId().toString()); + QPixmap pic; + pic.load(QDir(Settings::getInstance().getSettingsDirPath()).filePath("avatar.png")); if (!pic.isNull() && !pic.size().isEmpty()) { QByteArray data; @@ -218,12 +219,25 @@ void Core::start() buffer.open(QIODevice::WriteOnly); pic.save(&buffer, "PNG"); buffer.close(); - if (tox_set_avatar(tox, TOX_AVATAR_FORMAT_PNG, (uint8_t*)data.constData(), data.size()) != 0) - qWarning() << "Core:start: Error setting avatar, size:"<.png duplicate of avatar.png, but whatever + if (!pic.isNull() && !pic.size().isEmpty()) + { + QByteArray data; + QBuffer buffer(&data); + buffer.open(QIODevice::WriteOnly); + pic.save(&buffer, "PNG"); + buffer.close(); + setAvatar(TOX_AVATAR_FORMAT_PNG, data); + } + else + qDebug() << "Core: Error loading self avatar"; + } bootstrapDht(); @@ -476,7 +490,8 @@ void Core::onAvatarDataCallback(Tox*, int32_t friendnumber, uint8_t, else { qDebug() << "Core: Got avatar data from "<(core)->getFriendAddress(friendnumber)); + Settings::getInstance().saveAvatar(pic, static_cast(core)->getFriendAddress(friendnumber).left(64)); + // ignore nospam (good idea, and also the addFriend funcs which call getAvatar don't have it) emit static_cast(core)->friendAvatarChanged(friendnumber, pic); } } @@ -789,13 +804,10 @@ void Core::setAvatar(uint8_t format, const QByteArray& data) QPixmap pic; pic.loadFromData(data); - Settings::getInstance().saveAvatar(pic, getSelfId().toString()); + QString path = QDir(Settings::getInstance().getSettingsDirPath()).filePath("avatar.png"); + pic.save(path, "png"); emit selfAvatarChanged(pic); - - // Broadcast our new avatar! - const uint32_t friendCount = tox_count_friendlist(tox);; - for (unsigned i=0; i const QString Settings::FILENAME = "settings.ini"; -const QString Settings::AVATAR_FILENAME = "avatar.dat"; bool Settings::makeToxPortable{false}; Settings::Settings() : @@ -260,15 +259,27 @@ QString Settings::getSettingsDirPath() QPixmap Settings::getSavedAvatar(const QString &ownerId) { - QString filePath = QDir(getSettingsDirPath()).filePath("avatar_"+ownerId); + QDir dir(getSettingsDirPath()); + QString filePath = dir.filePath("avatars/"+ownerId+".png"); + QFileInfo info(filePath); QPixmap pic; - pic.load(filePath); + if (!info.exists()) + { + QString filePath = dir.filePath("avatar_"+ownerId); + pic.load(filePath); + saveAvatar(pic, ownerId); + QFile::remove(filePath); + } + else + pic.load(filePath); return pic; } void Settings::saveAvatar(QPixmap& pic, const QString& ownerId) { - QString filePath = QDir(getSettingsDirPath()).filePath("avatar_"+ownerId); + QDir dir(getSettingsDirPath()); + dir.mkdir("avatars/"); // remove this in a week or two hopefully + QString filePath = dir.filePath("avatars/"+ownerId+".png"); pic.save(filePath, "png"); } diff --git a/settings.h b/settings.h index 882a31f0f..b796211cb 100644 --- a/settings.h +++ b/settings.h @@ -142,7 +142,6 @@ private: Settings& operator=(const Settings&) = delete; static const QString FILENAME; - static const QString AVATAR_FILENAME; bool loaded; diff --git a/widget/widget.cpp b/widget/widget.cpp index a8f2ab683..3134b2ee6 100644 --- a/widget/widget.cpp +++ b/widget/widget.cpp @@ -477,7 +477,7 @@ void Widget::addFriend(int friendId, const QString &userId) connect(core, &Core::friendAvatarRemoved, newfriend->widget, &FriendWidget::onAvatarRemoved); // Try to get the avatar from the cache - QPixmap avatar = Settings::getInstance().getSavedAvatar(userId); + QPixmap avatar = Settings::getInstance().getSavedAvatar(userId.left(64)); // just to be safe if (!avatar.isNull()) { newfriend->chatForm->onAvatarChange(friendId, avatar); From f4c2bf9f345c62e0e577aab8f64cf91e2747c7df Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Sat, 27 Sep 2014 23:43:21 +0200 Subject: [PATCH 091/205] Update build scripts --- bootstrap.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bootstrap.sh b/bootstrap.sh index 9c67a7af9..d9bf32fe4 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -103,7 +103,7 @@ rm -rf ${BASE_DIR}/${TOX_CORE_DIR} # afterwards install libsodium to INSTALL_DIR # skip the installation if TOX_ONLY is true if [[ $TOX_ONLY = "false" ]]; then - git clone git://github.com/jedisct1/libsodium.git ${BASE_DIR}/${SODIUM_DIR} + git clone git://github.com/jedisct1/libsodium.git ${BASE_DIR}/${SODIUM_DIR} --depth 1 pushd ${BASE_DIR}/${SODIUM_DIR} git checkout tags/$SODIUM_VER ./autogen.sh @@ -116,7 +116,7 @@ if [[ $TOX_ONLY = "false" ]]; then make -j2 check - if [[ $GLOBAL = "false" ]]; then + if [[ $GLOBAL = "false" || $EUID -e 0 ]]; then make install else sudo make install @@ -128,7 +128,7 @@ fi # clone current master of libtoxcore # make sure to compile with libsodium we just installed to INSTALL_DIR # afterwards install libtoxcore to INSTALL_DIR -git clone https://github.com/irungentoo/toxcore.git ${BASE_DIR}/${TOX_CORE_DIR} +git clone https://github.com/irungentoo/toxcore.git ${BASE_DIR}/${TOX_CORE_DIR} --depth 1 pushd ${BASE_DIR}/${TOX_CORE_DIR} ./autogen.sh if [[ $GLOBAL = "false" ]]; then @@ -139,7 +139,7 @@ fi make -j2 -if [[ $GLOBAL = "false" ]]; then +if [[ $GLOBAL = "false" || $EUID -e 0 ]]; then make install else sudo make install From b1b89ac1f43a23065862e04ab0046349a4e7ae6d Mon Sep 17 00:00:00 2001 From: dubslow Date: Sat, 27 Sep 2014 16:44:08 -0500 Subject: [PATCH 092/205] minor --- core.cpp | 4 ++-- widget/widget.cpp | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/core.cpp b/core.cpp index 32f614721..11a27b612 100644 --- a/core.cpp +++ b/core.cpp @@ -223,9 +223,9 @@ void Core::start() } else { - QPixmap pic = Settings::getInstance().getSavedAvatar(getSelfId().toString()); - qDebug() << "self avatar missing, trying by id"; + qDebug() << "Core: self avatar missing, trying by id"; // this will leave a avatars/.png duplicate of avatar.png, but whatever + QPixmap pic = Settings::getInstance().getSavedAvatar(getSelfId().toString()); if (!pic.isNull() && !pic.size().isEmpty()) { QByteArray data; diff --git a/widget/widget.cpp b/widget/widget.cpp index 3134b2ee6..40239a701 100644 --- a/widget/widget.cpp +++ b/widget/widget.cpp @@ -444,7 +444,7 @@ void Widget::setStatusMessage(const QString &statusMessage) void Widget::addFriend(int friendId, const QString &userId) { - qDebug() << "Widget: Adding friend with id "+userId; + qDebug() << "Widget: Adding friend with id" << userId; Friend* newfriend = FriendList::addFriend(friendId, userId); QLayout* layout = contactListWidget->getFriendLayout(Status::Offline); layout->addWidget(newfriend->widget); @@ -480,6 +480,7 @@ void Widget::addFriend(int friendId, const QString &userId) QPixmap avatar = Settings::getInstance().getSavedAvatar(userId.left(64)); // just to be safe if (!avatar.isNull()) { + qWarning() << "Widget: loadded avatar for id" << userId; newfriend->chatForm->onAvatarChange(friendId, avatar); newfriend->widget->onAvatarChange(friendId, avatar); } From 78b9553f4f3a7451d3fe7ae91b849ac89e8f20ac Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Sat, 27 Sep 2014 23:51:02 +0200 Subject: [PATCH 093/205] Update build scripts --- bootstrap.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bootstrap.sh b/bootstrap.sh index d9bf32fe4..95a11febe 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -116,7 +116,7 @@ if [[ $TOX_ONLY = "false" ]]; then make -j2 check - if [[ $GLOBAL = "false" || $EUID -e 0 ]]; then + if [[ $GLOBAL = "false" || $EUID -eq 0 ]]; then make install else sudo make install @@ -139,7 +139,7 @@ fi make -j2 -if [[ $GLOBAL = "false" || $EUID -e 0 ]]; then +if [[ $GLOBAL = "false" || $EUID -eq 0 ]]; then make install else sudo make install From 766bd6e929cf1a351107e3149f1feb6239695a12 Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Sun, 28 Sep 2014 00:09:40 +0200 Subject: [PATCH 094/205] Update build scripts --- debian/control | 2 +- tools/buildPackages.sh | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/debian/control b/debian/control index 093a912a2..1ac14b28c 100644 --- a/debian/control +++ b/debian/control @@ -3,7 +3,7 @@ Maintainer: John Smith Section: misc Priority: optional Standards-Version: 3.9.5 -Build-Depends: debhelper (>= 9), cdbs, qt5-qmake, libopenal-dev, libopencv-dev, libopus-dev, qtbase5-dev +Build-Depends: debhelper (>= 9), cdbs, qt5-qmake, libopenal-dev, libopencv-dev, libopus-dev, qtbase5-dev, sudo, autoconf Package: qtox Architecture: any diff --git a/tools/buildPackages.sh b/tools/buildPackages.sh index e028670e5..81ec614d5 100755 --- a/tools/buildPackages.sh +++ b/tools/buildPackages.sh @@ -87,6 +87,7 @@ mv qTox-master $VERNAME # Build packages cd $VERNAME +./bootstrap.sh debuild -us -uc cd .. From 2047f8dc8ddee004a2465e79069b2fd92913249a Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Sun, 28 Sep 2014 00:14:49 +0200 Subject: [PATCH 095/205] Update build scripts --- tools/buildPackages.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/buildPackages.sh b/tools/buildPackages.sh index 81ec614d5..365cfd81d 100755 --- a/tools/buildPackages.sh +++ b/tools/buildPackages.sh @@ -56,9 +56,9 @@ done if [[ $OPT_APT = "true" ]]; then echo "Installing missing tools (if any)..." if [[ $EUID -ne 0 && $OPT_SUDO = "true" ]]; then - sudo apt-get install wget debhelper cdbs devscripts alien tar gzip build-essential -y + sudo apt-get install wget debhelper cdbs devscripts alien tar gzip build-essential sudo autoconf -y else - apt-get install wget debhelper cdbs devscripts alien tar gzip build-essential -y + apt-get install wget debhelper cdbs devscripts alien tar gzip build-essential sudo autoconf -y fi fi From eb67f9b3dd90f745f050d09658fdb98ce883bb9d Mon Sep 17 00:00:00 2001 From: dubslow Date: Sat, 27 Sep 2014 17:19:30 -0500 Subject: [PATCH 096/205] revert special self avatar --- core.cpp | 33 ++++++++++----------------------- settings.cpp | 9 ++++++--- widget/widget.cpp | 2 +- 3 files changed, 17 insertions(+), 27 deletions(-) diff --git a/core.cpp b/core.cpp index 11a27b612..9b7f7913c 100644 --- a/core.cpp +++ b/core.cpp @@ -210,8 +210,7 @@ void Core::start() tox_get_address(tox, friendAddress); emit friendAddressGenerated(CFriendAddress::toString(friendAddress)); - QPixmap pic; - pic.load(QDir(Settings::getInstance().getSettingsDirPath()).filePath("avatar.png")); + QPixmap pic = Settings::getInstance().getSavedAvatar(getSelfId().toString()); if (!pic.isNull() && !pic.size().isEmpty()) { QByteArray data; @@ -222,22 +221,7 @@ void Core::start() setAvatar(TOX_AVATAR_FORMAT_PNG, data); } else - { - qDebug() << "Core: self avatar missing, trying by id"; - // this will leave a avatars/.png duplicate of avatar.png, but whatever - QPixmap pic = Settings::getInstance().getSavedAvatar(getSelfId().toString()); - if (!pic.isNull() && !pic.size().isEmpty()) - { - QByteArray data; - QBuffer buffer(&data); - buffer.open(QIODevice::WriteOnly); - pic.save(&buffer, "PNG"); - buffer.close(); - setAvatar(TOX_AVATAR_FORMAT_PNG, data); - } - else - qDebug() << "Core: Error loading self avatar"; - } + qDebug() << "Core: Error loading self avatar"; bootstrapDht(); @@ -490,8 +474,7 @@ void Core::onAvatarDataCallback(Tox*, int32_t friendnumber, uint8_t, else { qDebug() << "Core: Got avatar data from "<(core)->getFriendAddress(friendnumber).left(64)); - // ignore nospam (good idea, and also the addFriend funcs which call getAvatar don't have it) + Settings::getInstance().saveAvatar(pic, static_cast(core)->getFriendAddress(friendnumber)); emit static_cast(core)->friendAvatarChanged(friendnumber, pic); } } @@ -804,10 +787,14 @@ void Core::setAvatar(uint8_t format, const QByteArray& data) QPixmap pic; pic.loadFromData(data); - QString path = QDir(Settings::getInstance().getSettingsDirPath()).filePath("avatar.png"); - pic.save(path, "png"); + Settings::getInstance().saveAvatar(pic, getSelfId().toString()); emit selfAvatarChanged(pic); - // according to tox.h, we need not broadcast ourselves, that's done in tox_set_avatar + + // Broadcast our new avatar! + // according to tox.h, we need not broadcast this ourselves, but initial testing indicated elsewise + const uint32_t friendCount = tox_count_friendlist(tox);; + for (unsigned i=0; iwidget, &FriendWidget::onAvatarRemoved); // Try to get the avatar from the cache - QPixmap avatar = Settings::getInstance().getSavedAvatar(userId.left(64)); // just to be safe + QPixmap avatar = Settings::getInstance().getSavedAvatar(userId); if (!avatar.isNull()) { qWarning() << "Widget: loadded avatar for id" << userId; From 2c224b6f3a535668060711fa2864397e95f8d1cc Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Sun, 28 Sep 2014 00:19:40 +0200 Subject: [PATCH 097/205] Update build scripts --- debian/control | 2 +- tools/buildPackages.sh | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/debian/control b/debian/control index 1ac14b28c..78fb30e54 100644 --- a/debian/control +++ b/debian/control @@ -3,7 +3,7 @@ Maintainer: John Smith Section: misc Priority: optional Standards-Version: 3.9.5 -Build-Depends: debhelper (>= 9), cdbs, qt5-qmake, libopenal-dev, libopencv-dev, libopus-dev, qtbase5-dev, sudo, autoconf +Build-Depends: debhelper (>= 9), cdbs, qt5-qmake, libopenal-dev, libopencv-dev, libopus-dev, qtbase5-dev, sudo, autoconf, libtool, pkg-config Package: qtox Architecture: any diff --git a/tools/buildPackages.sh b/tools/buildPackages.sh index 365cfd81d..49f4eecbd 100755 --- a/tools/buildPackages.sh +++ b/tools/buildPackages.sh @@ -56,9 +56,9 @@ done if [[ $OPT_APT = "true" ]]; then echo "Installing missing tools (if any)..." if [[ $EUID -ne 0 && $OPT_SUDO = "true" ]]; then - sudo apt-get install wget debhelper cdbs devscripts alien tar gzip build-essential sudo autoconf -y + sudo apt-get install wget debhelper cdbs devscripts alien tar gzip build-essential sudo autoconf libtool pkg-config -y else - apt-get install wget debhelper cdbs devscripts alien tar gzip build-essential sudo autoconf -y + apt-get install wget debhelper cdbs devscripts alien tar gzip build-essential sudo autoconf libtool pkg-config -y fi fi From 8abcc3b77dd0eb0d48f500c98c51be96908f9153 Mon Sep 17 00:00:00 2001 From: dubslow Date: Sat, 27 Sep 2014 17:36:19 -0500 Subject: [PATCH 098/205] blasted scoping issue --- settings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings.cpp b/settings.cpp index 16e9332b8..3e9f33426 100644 --- a/settings.cpp +++ b/settings.cpp @@ -267,7 +267,7 @@ QPixmap Settings::getSavedAvatar(const QString &ownerId) { QString filePath = dir.filePath("avatar_"+ownerId.left(64)); if (!QFileInfo(filePath).exists()) // try without truncation, for old self avatars - QString filePath = dir.filePath("avatar_"+ownerId); + filePath = dir.filePath("avatar_"+ownerId); pic.load(filePath); saveAvatar(pic, ownerId); QFile::remove(filePath); From 35f548c3a1b66278079aabc64698bfeeb11701dc Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Sun, 28 Sep 2014 00:43:01 +0200 Subject: [PATCH 099/205] Update build scripts --- debian/control | 2 +- tools/buildPackages.sh | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/debian/control b/debian/control index 78fb30e54..7fa0cc2b4 100644 --- a/debian/control +++ b/debian/control @@ -3,7 +3,7 @@ Maintainer: John Smith Section: misc Priority: optional Standards-Version: 3.9.5 -Build-Depends: debhelper (>= 9), cdbs, qt5-qmake, libopenal-dev, libopencv-dev, libopus-dev, qtbase5-dev, sudo, autoconf, libtool, pkg-config +Build-Depends: debhelper (>= 9), cdbs, qt5-qmake, libopenal-dev, libopencv-dev, libopus-dev, qtbase5-dev, sudo, autoconf, libtool, pkg-config, libvpx-dev Package: qtox Architecture: any diff --git a/tools/buildPackages.sh b/tools/buildPackages.sh index 49f4eecbd..4e6b6e144 100755 --- a/tools/buildPackages.sh +++ b/tools/buildPackages.sh @@ -56,9 +56,9 @@ done if [[ $OPT_APT = "true" ]]; then echo "Installing missing tools (if any)..." if [[ $EUID -ne 0 && $OPT_SUDO = "true" ]]; then - sudo apt-get install wget debhelper cdbs devscripts alien tar gzip build-essential sudo autoconf libtool pkg-config -y + sudo apt-get install wget debhelper cdbs devscripts alien tar gzip build-essential sudo autoconf libtool pkg-config libvpx-dev -y else - apt-get install wget debhelper cdbs devscripts alien tar gzip build-essential sudo autoconf libtool pkg-config -y + apt-get install wget debhelper cdbs devscripts alien tar gzip build-essential sudo autoconf libtool pkg-config libvpx-dev -y fi fi From 21d084e258e37421c76b3a0eb36135534c0aa16e Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Sun, 28 Sep 2014 10:56:02 +0200 Subject: [PATCH 100/205] Compat with toxcore --- core.cpp | 8 ++++---- core.h | 6 +++--- widget/widget.cpp | 4 ++-- widget/widget.h | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/core.cpp b/core.cpp index 9b7f7913c..1b04c16ac 100644 --- a/core.cpp +++ b/core.cpp @@ -299,10 +299,10 @@ void Core::onAction(Tox*/* tox*/, int friendId, const uint8_t *cMessage, uint16_ emit static_cast(core)->actionReceived(friendId, CString::toString(cMessage, cMessageSize)); } -void Core::onGroupInvite(Tox*, int friendnumber, const uint8_t *group_public_key, void *core) +void Core::onGroupInvite(Tox*, int friendnumber, const uint8_t *group_public_key, uint16_t length,void *core) { qDebug() << QString("Core: Group invite by %1").arg(friendnumber); - emit static_cast(core)->groupInviteReceived(friendnumber, group_public_key); + emit static_cast(core)->groupInviteReceived(friendnumber, group_public_key,length); } void Core::onGroupMessage(Tox*, int groupnumber, int friendgroupnumber, const uint8_t * message, uint16_t length, void *core) @@ -1084,10 +1084,10 @@ QList Core::getGroupPeerNames(int groupId) const return names; } -int Core::joinGroupchat(int32_t friendnumber, const uint8_t* friend_group_public_key) const +int Core::joinGroupchat(int32_t friendnumber, const uint8_t* friend_group_public_key,uint16_t length) const { qDebug() << QString("Trying to join groupchat invite by friend %1").arg(friendnumber); - return tox_join_groupchat(tox, friendnumber, friend_group_public_key); + return tox_join_groupchat(tox, friendnumber, friend_group_public_key,length); } void Core::quitGroupChat(int groupId) const diff --git a/core.h b/core.h index 6704628b1..253ccb401 100644 --- a/core.h +++ b/core.h @@ -42,7 +42,7 @@ public: QString getGroupPeerName(int groupId, int peerId) const; QList getGroupPeerNames(int groupId) const; QString getFriendAddress(int friendNumber) const; - int joinGroupchat(int32_t friendnumber, const uint8_t* friend_group_public_key) const; + int joinGroupchat(int32_t friendnumber, const uint8_t* friend_group_public_key,uint16_t length) const; void quitGroupChat(int groupId) const; void dispatchVideoFrame(vpx_image img) const; @@ -119,7 +119,7 @@ signals: void friendLastSeenChanged(int friendId, const QDateTime& dateTime); void emptyGroupCreated(int groupnumber); - void groupInviteReceived(int friendnumber, const uint8_t *group_public_key); + void groupInviteReceived(int friendnumber, const uint8_t *group_public_key,uint16_t length); void groupMessageReceived(int groupnumber, int friendgroupnumber, const QString& message); void groupNamelistChanged(int groupnumber, int peernumber, uint8_t change); @@ -178,7 +178,7 @@ private: static void onUserStatusChanged(Tox* tox, int friendId, uint8_t userstatus, void* core); static void onConnectionStatusChanged(Tox* tox, int friendId, uint8_t status, void* core); static void onAction(Tox* tox, int friendId, const uint8_t* cMessage, uint16_t cMessageSize, void* core); - static void onGroupInvite(Tox *tox, int friendnumber, const uint8_t *group_public_key, void *userdata); + static void onGroupInvite(Tox *tox, int friendnumber, const uint8_t *group_public_key, uint16_t length,void *userdata); static void onGroupMessage(Tox *tox, int groupnumber, int friendgroupnumber, const uint8_t * message, uint16_t length, void *userdata); static void onGroupNamelistChange(Tox *tox, int groupnumber, int peernumber, uint8_t change, void *userdata); static void onFileSendRequestCallback(Tox *tox, int32_t friendnumber, uint8_t filenumber, uint64_t filesize, diff --git a/widget/widget.cpp b/widget/widget.cpp index af1d33034..c8c24187d 100644 --- a/widget/widget.cpp +++ b/widget/widget.cpp @@ -633,9 +633,9 @@ void Widget::copyFriendIdToClipboard(int friendId) } } -void Widget::onGroupInviteReceived(int32_t friendId, const uint8_t* publicKey) +void Widget::onGroupInviteReceived(int32_t friendId, const uint8_t* publicKey,uint16_t length) { - int groupId = core->joinGroupchat(friendId, publicKey); + int groupId = core->joinGroupchat(friendId, publicKey,length); if (groupId == -1) { qWarning() << "Widget::onGroupInviteReceived: Unable to accept invitation"; diff --git a/widget/widget.h b/widget/widget.h index dd6c8180e..5ec25b501 100644 --- a/widget/widget.h +++ b/widget/widget.h @@ -98,7 +98,7 @@ private slots: void onFriendMessageReceived(int friendId, const QString& message); void onFriendRequestReceived(const QString& userId, const QString& message); void onEmptyGroupCreated(int groupId); - void onGroupInviteReceived(int32_t friendId, const uint8_t *publicKey); + void onGroupInviteReceived(int32_t friendId, const uint8_t *publicKey,uint16_t length); void onGroupMessageReceived(int groupnumber, int friendgroupnumber, const QString& message); void onGroupNamelistChanged(int groupnumber, int peernumber, uint8_t change); void removeFriend(int friendId); From 12380bc39776569b394f463bd811738c2bbf7514 Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Sun, 28 Sep 2014 10:59:49 +0200 Subject: [PATCH 101/205] Allow non-png avatars, convert them on the fly --- widget/widget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/widget/widget.cpp b/widget/widget.cpp index c8c24187d..7c38847a6 100644 --- a/widget/widget.cpp +++ b/widget/widget.cpp @@ -284,7 +284,7 @@ Camera* Widget::getCamera() void Widget::onAvatarClicked() { - QString filename = QFileDialog::getOpenFileName(this, tr("Choose a profile picture"), QDir::homePath(), "*.png"); + QString filename = QFileDialog::getOpenFileName(this, tr("Choose a profile picture"), QDir::homePath()); if (filename == "") return; QFile file(filename); From aa6fbc9e284ea904b598133470bf8b5b3d0fa273 Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Sun, 28 Sep 2014 11:19:58 +0200 Subject: [PATCH 102/205] MaskablePixmapWidget should update() on setPixmap Fixes our own avatar apparently not changing until qTox restarted --- widget/maskablepixmapwidget.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/widget/maskablepixmapwidget.cpp b/widget/maskablepixmapwidget.cpp index 305eb015c..966143a0a 100644 --- a/widget/maskablepixmapwidget.cpp +++ b/widget/maskablepixmapwidget.cpp @@ -39,6 +39,7 @@ void MaskablePixmapWidget::setClickable(bool clickable) void MaskablePixmapWidget::setPixmap(const QPixmap &pmap) { pixmap = pmap.scaled(width(), height(), Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation); + update(); } QPixmap MaskablePixmapWidget::getPixmap() const From 87c9bbf1e6f7565bcf8aba7cb1f61dea004912e9 Mon Sep 17 00:00:00 2001 From: krepa098 Date: Sun, 28 Sep 2014 17:30:00 +0200 Subject: [PATCH 103/205] fixes #332, #334 and other visual glitches --- img/contact.png | Bin 790 -> 1170 bytes img/contact_dark.png | Bin 744 -> 1532 bytes img/group.png | Bin 512 -> 1639 bytes img/group_2x.png | Bin 0 -> 512 bytes img/group_dark.png | Bin 671 -> 2262 bytes mainwindow.ui | 12 ++++++------ res.qrc | 1 + ui/friendList/friendList.css | 12 +++++------- widget/adjustingscrollarea.cpp | 22 ++++++++++++++++++++-- widget/adjustingscrollarea.h | 7 ++----- widget/groupwidget.cpp | 10 ++++++---- widget/groupwidget.h | 5 ++++- widget/maskablepixmapwidget.cpp | 6 +++++- 13 files changed, 49 insertions(+), 26 deletions(-) create mode 100644 img/group_2x.png diff --git a/img/contact.png b/img/contact.png index e98b4d7ec1c2aa9f2e25edebbb6e128cec17a8b3..3b495014424e134fd93eba1b275f2419f96c4038 100644 GIT binary patch literal 1170 zcmV;D1a13?P)K~#90<(f^1Rb?2*e{-EQz0IgGewBiS;zvd5xM^b`Ntlap z1Q!z$=t3cIW1+KXBS=`J2(FZ2R^q~Fp@j5-5iN=`6jU5PQpzv+gUbe3J)Q46L()S+;-za1EGl1&q)+V7>*&vIQ(Bo8$rJ5k9C=%hG_=hO9VRV*#-= zpwo~QM=LELR%1W`7yu?%z+&nF&_>GHz^VmIB-`WxionZhAyx*o8F7+oR$73S0eLMe zO-u{0GT=J!*oc)x#k2q`1D*g^jaW%^EiJ%u8a!{v%Iuw%1{^bF#nFA>Mp}ra0pA$1 z;^;dI0TVrhVY?+kfSDgj?vfUMU8vg!su0e37w&1!&2^9Oqat`o)r zZymM*d2Ee+=D@7fZ@^hAn8&K{7(#$^t-)ozjbT^wXaP@vPaL=qmcvcQ8Ly3zR^V4) zks-4LyaD`T$aLEte++a1cMX}_FiswP>jN$W?-72vwCclYaP=;bI7-+oNz>1MAk-DO zD2ob_Pl309KNCLp5cn8a0X(t}>OVPckJmcdCH2PK3O^=kZWeKQ%>q%H3M{QS766wB zo1Q1jM}Jnqs?7VD>!E)t(P>`DqgFk3zAkzI;!ZRs6QlqBxzCvt5wnpNe3f1Hzf5)nw&Ovi!op& zu$N@pRR0nNy;H#Ngf3D9W)hnE^D#LOfL`Epl25Zhxddu=2SJF1uPgZvZsfsxDt9{|T`yyO8k5dMY6t{zEhKo6n6Kb!EmEVYpEukrmj zHz(-=UBDN3%*8$`5eC$+qi%|8z!Km`vM+*2tG@`J+n4Lz5T^^wAgsbRTk;U5(=UPX z^=^n`zz*O=tB7*YBEq;;Q^R$E*@P|VXKZ82TqQy-SE?@z*8;ZE{K-Seb3?5QQ7zyF z!r(F1DX6SAL+T3a8IZdEt^suu___LI klmVk{!{891c43g70&mlUPqG|57ytkO07*qoM6N<$g0JQQCjbBd literal 790 zcmV+x1L^#UP)JB0(4j;NPgQMG)2{Ho+ixU=b{YG_f>bp&)FPX0=-IYKs&>L?i?YL2D0U zrOo~U2|>0KHid$fV&Q=(v4}_rL=e=u%AARDzf63~*?H%g&*de-U=T)v>)74CF8WVu`# zMwiPaI-L$N4Ns?2)a!M_aJ^o~bUNMb2lDXnU>MeuqX{dDLS$LijmokNMNxMDR|7z~ zTt>Is)$G^pc2O>ubxlwgJQ|Hip-@1h(b(Fj(P*GhC}1=i>3aOcNFi`=aDYf8LQhXm zv0ex?n@!x^-I2Gqx9=+itX3;*HXCNM*@yPS!$S!G#^dqDdOO1~n9t`}EEeXsn&){c zNfH$Vfqwor9*-|RqW~ZX0+l3*@;pxsub5?7&*kN1FAxa4x8-s<)M_==^9zMS^y=zr z{Y4<3&;NRPdHJgeyId}MeSHnL+r2SxrBXq)S|y*ionaUVf+NCB;q`iZmR(BNT}oez-EQAIY`5F-5B#0` UTOjxRz5oCK07*qoM6N<$g6!UGM*si- diff --git a/img/contact_dark.png b/img/contact_dark.png index 584a4669e5fc03f8021187a32de68d72dceeb8ca..a1c77479a56b7a5d63b2e534d5cd8bff8a638209 100644 GIT binary patch literal 1532 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 literal 512 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 FV1k2$D3$;K diff --git a/mainwindow.ui b/mainwindow.ui index a197594bd..385ecb489 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -6,8 +6,8 @@ 0 0 - 714 - 541 + 712 + 539 @@ -2083,8 +2083,8 @@ QSplitter:handle{ 0 0 - 262 - 375 + 261 + 373 @@ -2587,7 +2587,7 @@ QSplitter:handle{ - :/img/group.png:/img/group.png + :/img/group_2x.png:/img/group_2x.png true @@ -3218,7 +3218,7 @@ QSplitter:handle{ 0 0 - 714 + 712 25 diff --git a/res.qrc b/res.qrc index 603fc8ba2..d085ca820 100644 --- a/res.qrc +++ b/res.qrc @@ -143,5 +143,6 @@ translations/fi.qm translations/mannol.qm img/avatar_mask.png + img/group_2x.png diff --git a/ui/friendList/friendList.css b/ui/friendList/friendList.css index 55b39e1e6..8358f5a04 100644 --- a/ui/friendList/friendList.css +++ b/ui/friendList/friendList.css @@ -3,18 +3,16 @@ QScrollArea { } QScrollBar:vertical { - background: transparent; - width: 14px; - margin-top: 2px; - margin-bottom: 2px; + background: rgb(65,65,65); + width: 16px; + padding: 0px 3px 0px 3px; } QScrollBar:handle:vertical { background: rgba(18, 18, 18, 204); min-height: 20px; - border-radius: 3px; - margin-left: 3px; - margin-right: 1px; + border-radius: 5px; + margin: 3px 0px 3px 0px; } QScrollBar:handle:vertical:hover { diff --git a/widget/adjustingscrollarea.cpp b/widget/adjustingscrollarea.cpp index bb273fa90..2bd9cd3e8 100644 --- a/widget/adjustingscrollarea.cpp +++ b/widget/adjustingscrollarea.cpp @@ -21,14 +21,19 @@ #include #include -AdjustingScrollArea::AdjustingScrollArea(QWidget *parent) : - QScrollArea(parent) +AdjustingScrollArea::AdjustingScrollArea(QWidget *parent) + : QScrollArea(parent) { } void AdjustingScrollArea::resizeEvent(QResizeEvent *ev) { + int scrollBarWidth = verticalScrollBar()->isVisible() ? verticalScrollBar()->sizeHint().width() : 0; + + if (layoutDirection() == Qt::RightToLeft) + setViewportMargins(-scrollBarWidth, 0, 0, 0); + updateGeometry(); QScrollArea::resizeEvent(ev); } @@ -43,3 +48,16 @@ QSize AdjustingScrollArea::sizeHint() const return QScrollArea::sizeHint(); } + +bool AdjustingScrollArea::eventFilter(QObject *obj, QEvent *ev) +{ + if (ev->type() == QEvent::Paint) + { + // workaround: sometimes a child widget gets drawn on top of the scrollbar + // so we trigger a repaint afterwards + verticalScrollBar()->update(); + horizontalScrollBar()->update(); + } + + return QObject::eventFilter(obj, ev); +} diff --git a/widget/adjustingscrollarea.h b/widget/adjustingscrollarea.h index a1645cbba..380ac5df8 100644 --- a/widget/adjustingscrollarea.h +++ b/widget/adjustingscrollarea.h @@ -25,12 +25,9 @@ class AdjustingScrollArea : public QScrollArea public: explicit AdjustingScrollArea(QWidget *parent = 0); - virtual void resizeEvent(QResizeEvent *ev); + virtual void resizeEvent(QResizeEvent *ev) override; virtual QSize sizeHint() const override; -signals: - -public slots: - + virtual bool eventFilter(QObject *obj, QEvent *ev) override; }; #endif // ADJUSTINGSCROLLAREA_H diff --git a/widget/groupwidget.cpp b/widget/groupwidget.cpp index b8c1cbcc0..7bd1683c9 100644 --- a/widget/groupwidget.cpp +++ b/widget/groupwidget.cpp @@ -19,6 +19,7 @@ #include "group.h" #include "settings.h" #include "widget/form/groupchatform.h" +#include "widget/maskablepixmapwidget.h" #include #include #include @@ -38,7 +39,8 @@ GroupWidget::GroupWidget(int GroupId, QString Name) textLayout.setMargin(0); setLayoutDirection(Qt::LeftToRight); // parent might have set Qt::RightToLeft - avatar.setPixmap(QPixmap(":img/group.png")); + avatar = new MaskablePixmapWidget(this, QSize(40,40), QString(), Qt::transparent); + avatar->setPixmap(QPixmap(":img/group.png")); statusPic.setPixmap(QPixmap(":img/status/dot_online.png")); name.setText(Name); QFont small; @@ -65,7 +67,7 @@ GroupWidget::GroupWidget(int GroupId, QString Name) textLayout.addStretch(); layout.addSpacing(20); - layout.addWidget(&avatar); + layout.addWidget(avatar); layout.addSpacing(5); layout.addLayout(&textLayout); layout.addStretch(); @@ -118,7 +120,7 @@ void GroupWidget::setAsActiveChatroom() QPalette pal3; pal3.setColor(QPalette::Background, Qt::white); this->setPalette(pal3); - avatar.setPixmap(QPixmap(":img/group_dark.png")); + avatar->setPixmap(QPixmap(":img/group_dark.png")); } void GroupWidget::setAsInactiveChatroom() @@ -137,7 +139,7 @@ void GroupWidget::setAsInactiveChatroom() QPalette pal3; pal3.setColor(QPalette::Background, QColor(65,65,65,255)); this->setPalette(pal3); - avatar.setPixmap(QPixmap(":img/group.png")); + avatar->setPixmap(QPixmap(":img/group.png")); } void GroupWidget::updateStatusLight() diff --git a/widget/groupwidget.h b/widget/groupwidget.h index 54d1ee533..960ab9cb7 100644 --- a/widget/groupwidget.h +++ b/widget/groupwidget.h @@ -20,6 +20,8 @@ #include #include "genericchatroomwidget.h" +class MaskablePixmapWidget; + class GroupWidget : public GenericChatroomWidget { Q_OBJECT @@ -39,7 +41,8 @@ signals: public: int groupId; - QLabel avatar, name, nusers, statusPic; + QLabel name, nusers, statusPic; + MaskablePixmapWidget* avatar; }; #endif // GROUPWIDGET_H diff --git a/widget/maskablepixmapwidget.cpp b/widget/maskablepixmapwidget.cpp index 966143a0a..90eaf9552 100644 --- a/widget/maskablepixmapwidget.cpp +++ b/widget/maskablepixmapwidget.cpp @@ -23,7 +23,11 @@ MaskablePixmapWidget::MaskablePixmapWidget(QWidget *parent, QSize size, QString , clickable(false) { setFixedSize(size); - mask = QPixmap(maskName).scaled(size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + + QPixmap pmapMask = QPixmap(maskName); + + if (!pmapMask.isNull()) + mask = QPixmap(maskName).scaled(size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); } void MaskablePixmapWidget::setClickable(bool clickable) From 4ccfd8350533f0e3bcf45d944f732c73f9bb6ddf Mon Sep 17 00:00:00 2001 From: apprb Date: Sun, 28 Sep 2014 22:57:17 +0700 Subject: [PATCH 104/205] long name in file transfer widget fix --- filetransferinstance.cpp | 15 +++++++++++---- filetransferinstance.h | 1 + 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/filetransferinstance.cpp b/filetransferinstance.cpp index 6167bfac3..f8b10ecc8 100644 --- a/filetransferinstance.cpp +++ b/filetransferinstance.cpp @@ -23,6 +23,8 @@ #include #include +#define CONTENT_WIDTH 250 + uint FileTransferInstance::Idconter = 0; FileTransferInstance::FileTransferInstance(ToxFile File) @@ -34,6 +36,11 @@ FileTransferInstance::FileTransferInstance(ToxFile File) remotePaused = false; filename = File.fileName; + QFont font; + font.setPixelSize(10); + QFontMetrics fm(font); + filenameElided = fm.elidedText(filename, Qt::ElideRight, CONTENT_WIDTH); + size = getHumanReadableSize(File.filesize); speed = "0B/s"; eta = "00:00"; @@ -328,7 +335,7 @@ QString FileTransferInstance::drawButtonlessForm(const QString &type) imgBStr = ""; } - QString content = "

" + filename + "

" + size + "

"; + QString content = "

" + filenameElided + "

" + size + "

"; return wrapIntoForm(content, type, imgAStr, imgBStr); } @@ -354,9 +361,9 @@ QString FileTransferInstance::draw2ButtonsForm(const QString &type, const QImage QString imgBstr = ""; QString content; - QString progrBar = ""; + QString progrBar = ""; - content = "

" + filename + "

"; + content = "

" + filenameElided + "

"; content += ""; content += ""; content += ""; @@ -375,7 +382,7 @@ QString FileTransferInstance::wrapIntoForm(const QString& content, const QString res = "
" + size + "" + speed + "
\n"; res += "\n"; res += insertMiniature(type); - res += "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%0A;MIVIyvy1RuQ!;YPl<)@Tb0v`Q=7a7a+-fm z)TCiipH=0}d1cm8VHTqFbHKT3JLX)C%QN`%DxKq?3d!h?TQjC** zu}Gkly)3_0v`um;}|_?h>#AMrRVhqy?ViHkUkyo8R))5ac^48yQ19Bbr;e@=21@0ed`MROQy zL*B9JI4z%ndh&(F@BA=a&zr$*JUiUY!|*y!2lI$a;GD<>ddhVwpZZ!A2fxemFjX8g z>WiIdF;7EMSv9jI%V{;G(EjMnvd_6my1PA8>o6_{^0>*G({eFT#2X$6`A_wZmSDTI zs&$YpHEZ%JW@SE`l;9OfVICxmwI#`HIr)R-GFz~r=36?{98PDM4QVH{4t0o4XOeH} zG(4Z$=mwn*nXY4ht4SW4w5~H3f6CtS%e1pBN@L3RN5BBRZ8W6i@qRjvY+&om&V05N zsx|Kr24fuEr)>yZz&4N$&{x=%gb_PHDU(b`%YXZAI5&`Ed@t zd)0AEnq$1eRz8}?9>z}EcX;K%zv9P0W;HEP4-5`ehA40mwzD6>4c1J!&@2g?kZa&4 zTu;xw-c_YhU$xN4q#EcRaY*k2Ltz<^3>X*%f<{%)5^YywFq5MQ(p?*eN6eypsRh|f ztDhflZ+Blw&aW4s@bRw2M4UVE^`b7j!K zFP{0i#Cy7f*Woqz*K(Y$FEZXrGsNrR9kQZ1PF=IcfbxMVuz0W$Y#uBIy9Q5#R>3za zU+}p+9Jnt&+Wq-eYcaiITK+Neotr?s*w5IA1u=-_#@l0u@nB~Yx#>PM`}s-wUgium z6^8?ZWk4(7a|U%r5jYM823~S&?YuNc$8)_fam95tSmog^HIjlJwKPg#C!G(m1kQ=hG$b@l^$2zn;lQ`- zZ>z25V~%luA<*fHi^o2q57GU|jV7b-VtepZXCf)!^);XST`We=SVcLr{^d38ZsLJ; zMijH&it*-lU5S6nJK`jsAB|(a?juA%Ntz$D^?y+_bYHQW_q*)nCCE440&&x?A@0(6 zQBA8^{}wehS^pTbU~%@q*g${4wdoEr*#FBsvWE6gtW;n<`!_I^6%Q_E zoq{`9mf#_FAaH{%weK=)ePNTyCsrI&-D_yY18^VzOU)HWBv5%}3y>_vz_fC?F-+b; z+hr>5q+XI)YK6H_y)h@Ma+a&l=^C=FRYp+V{Z40wse=o8xo~?2qy5p+#_&jcxI5K^ zBT`?2VX4*N_SB%UHWD#jM0G98*@EY|-{=nSPF(zwmeIH=j9%R;9fWCZ=CQHv&_f=WN;b(aUb(P1- z-(slsi#TiF;4pYk*DwSPgnH6%Lp5o>P#2mv)Q|odJWm@2^RQn6yV+5@7Jp@(=5?($ zqQ2EZ0IR3SVb#-dCg%-phj$5F=DUJJ`LR$go-X{7RnX^BQn(Ns6M9a63Lc@??X&cR z*@>>jjp+)b89fcA>(!Hv?G;a1FCG??SsmGh4OiV*JusG4hUb`VbmJe4PkbY4A>QiR zUT2JiMY?NB*&sHX450Oi^w!{12k1<>8yXx5qjIUUjRq<8jJTAJM%9#c#^96&sAFmz zo*a3MbH^@`c}^$uu6xn^;1#w0_4`{dXeV8l&SbUMN`wv^m|1yY@<=}^7ujtzo)trl z*jpo!%`slk!bW!X9)4o2;Y~gX92A+rJ>6Sv4H~L+#%(zh<(BVoA@PGbm2b6vVn^&6 zbWz|R4+Ph_uL6&qzXBVb=YhdaufQrN7})Lfv(vaAti>)jeK((3*0art-d%FqJ5J*K zH6(}sUia<(FkAa8t#bZQ`-sQvfm%~s+)ERPx?k+;?lK#Aw=7MpHT!xDKleJLzJA!K zMel=VY_;mg+eo0@=Psyn;%8V+=wzQHMUa{%~R0>|Ce_68@XUD~N=XLP37(byL|hchN{$;lM_%iR@x z;S~;b(KWpw9UB@%=jw`B-q2n)I9QpV3N+_i?Ce_IAsHh!zo1vpB=nSxG*+@nusiDm z#<9)H=5u6UzDWF`-H4OKJ$6YHX1io}dPL3ir+_EkKG@JZVyto3qV3u_=29#dc^92V zszy(dJCRK0Uy<_W)kt>JiaMmRc11WFH3*0`!=qvu@PDyFxQz2gvtOQ|4^9k~cOT&+ z?oqnq>1JNwn_13t8iQ{S9GFOm?OfG4rWs01%%EVv#dhALrkWJW zChrBu@e09DbVQ)L|4LU6y4a1}I`#+W2Yaz|${ymh(T}S2k*C~g_DVvRvZP;=# zQ^zIuSUtXoUuL~TcD7&kqboHR8NzISW@D>Y6hY6{-R*mLq0@#WI-ALtSinq;jWUy* zT{;H6Y2I`u=r}ZsdEK2)DtiscR<9Geb{y*% zsLl2UhO%dYMLI^E$F2s>Gc!PSoNw_uWH(eGfUtHu%&vXW!}e=2z?#etYX?nY-t+R1Jno_Y zou(V3`Ek~0aeOs09RC){NlHYo5*i(CmUaqS#odWkYj3}0`k$;L{&{OHouOxxYU$JT zu&HO}%|7gyJ`rBvqO1r8tOL42*BeXeEx4F|3op^jpghYC*0KdUD|F?*e7{U5Ys&HJ zh@RZaE9w}B_!2Zgzqfx_Q8O#cYW1SOS;zf%*0+8k`-wNgUgfQ}yLy9kzdomZ(cP~p zsixK59b%SnzcK%Fpn1|sCfoG2#OZE6c9N`YZlYbv{cQJlJL=qjXyBdOG!XQP20puY z?RT!UKDv|5|MOhG>$?BvdJDUInE~)m%SBp~xPm_99$Uj3h+}-5Jj-9HkZ1~ri33JP zc>@iUGx0K6pNy8tB&QsqodW+dAMu-7jkUlmL+hFcyhO8zThY7_>uj!%&NquiLsq%y zN~>wKr~OZ~X5ezn3>I;(27mD?gr@t`Lo?{jP&0N-J8F#$30)ufMKlaf6?+3^M7jVG zU2QBrTS=mdl}YS2&+ve$tB>Ri=eUfffbACRQE_Rad$NmhUmbu6(1LMBdhpJus{o#( z_tMj17rDx-n&;V8^DMn&-uLflRYpduo0r+T>lU*rx`nM9T9q}=nQk_47|G-uBk7%u z#MaS>?X)IYowlT{vy1F-@|$;^^ColNnYG;W<_LGZImc~kj&)PXXtx;o-u;L&x!n!! z#DMRZpop7O{q2TjZ?BkG?*G9*>mFEB{)Go+Ch?={BtC%4qNPz*b7tC0h`Y;WxQ;AN zQpG4zN30=3w0dV08%YY#;(E2b$0OZmc#va~tFb1UEq+tKvf*Y&r-=2RBdp8rIUD(7 z0u5-!V18Y{zQAS&zv2^u%XqqA7BN21Q+Rd-QQqFbXIT09RnuiH%>@1rNyjIXd#oJ! z$S&YUd^CQ}v*I4&gszr1LBGjE#uioDI1DDkEATKlYLozX&?dDJ$En7e?RlPb746Jh z{8ya^?a=p@nnPI+s}h@Hn!Yes(5B{Mn!}t()9d&>QGXt1{zWsJ59vBH zfz`0`usB;Q8SLqd1b$;_0>870fr+e1pfkgPX6$Rbj#klBW+zE*b{JP-`_V17(P+T0 zL60|pROEt4<$!rW4j2y`!1P9IsEnC#6&eR!G##eJ4PYhwFQ|!tnXii-}+Br3;&9)?Y-7C!GN)s-hma^ zR_N>fHJK9#v$mmmY;5o*OBcA!`dM#Tl)PtCaRFWw4dw~PRh|)!6RSbIRuR3B!@v|Z z9n=QDff#rP7U^Ex~EPWTi0BuAsIqAU8B)j?Tlbu`nPiYmG5 zQ7-3S^joaC_Gi0=i^ZmrZZVHMhz&P4IoEWT;=GySE;9>zL(DE-9&@*Mk397zk@H?b z(#^Y}CnxIQQ|<|r>@G+3z20c7*9ZOPwL!uwfX4fI^zV6OEThwmWJ-)tY&>kokAPt! zMfH>!R29`m76JQ2ad?^MHYf|D{%jj!G%r3v=i-C3ExAt*k@r-PleDa1Hn;gX%+7u`vyxv-D>oaO8T=P!Nq?7B+n;Rz=obsj_O}I|`U$~Q|NCGDIx5(n z778AtnF4p|ZVR&#CeeNcIoVp&k99OAu>SBCy9Vm<8Q>Hjrqx=tK`vQZcXAql18ON4 z3ig6>aFf>Qj0bOwG+-X;rIPS0*&qKT=Hf4GE}lZW;RJsm-s`r(lbrAH&e(XIKeij+ zjefz0q8Z4iXjw8P)`nEk4pNi!wb_}ZcmFxMQaMLY`u8DK-Hs&1siVK1ldN#A;fS*u z57a;FwVN9!dJoZ1uQ7V#y)_2-RgA~}Y*?4R0%vJnFrKwm&G|t2l{hSJi&EmE+{`zq zOnfpJ&Ax|)SZl*#8PQ968oj4$ut$54GCBt;sJmw&mSUz*tvRJxtyZ*}<>@-}ZoiE+ z%+F_)^iAuv*V=mSowZ!AvYpwVVYl@U+Z%nyPWD>{>eC5<-R<~+`w$QE zAo;^1uh?Bf(xUrXlo_Hrv6Ms5d;a5hv=mpI( z|Iz5nEUhG)3TJW~Ru*$WIqjVsP$!hHepK5*JvAO?RAJ+ud|`BvKj~P%D2|sq^easu z@5C1JS#&l7TK#Lv9M(Hg+4@h6wN8t9);!%kY$QHdpLm>of|s<{@jALnvDNOwD+MO; zkJ|NQXi(E-f{(R=?mo9epE=Uk>R=jiD)5!)WShdWPVhHmHs6k?Y3Rl}z*%{@EXgSNr8OZBd|g{u!;M9)T|V^--#yh|1AZ#vlW1=h5_NUoxQsQ2cd&Z#DON!)tStPLCjA@>q~UXPw<1of4yT8%u_t;S zFFCY}?FsE?uYy(dsc$sN z=>&(Wk%-FU;(`1|{vfe>FP5m9+R=Ni&i{_FKfq4vff_ys={*m;cS=C$bcXq2o8Zpq z12{aI(HI(?YwXruO=V&o&_A(%(eF+*oWY%ke{gT&CvK4Z;MF7Nymo|py$SXQl0?4~ z$?xYU6a2CS&^n|toj|(LspJIhMhdW=je6-d?W~Bg+HGM}bAL9{y2lLchEW-}HyZE$ zfl~DzFw)zIw|hQ5;1wgwy!LwSPteoqzmdlN8B*UrPU`tfbiKb1x#>3}Eopgu;%3#m zUS@KZLDG|l2^O#MEO8a*m(%fXUF&P76ndv-q6HwkcFsO-T+wG|Popo)j^=~Q=z*Gr z>!{r1fZRsP%TnfDaahkD6t^0R##VMw!?H!l!s5F5FCT55=cUcX{1Iu*7m|#;6?wqM zl4I<;t}z!hPqEhK8Kz@+_J_HT+13SC*?OwGwITjUM|X8ilOG_IRVL5aSo})IP7m0B z#=lzQnuafft$7-)zFY+E@)DqfIHwMaUMjtma=P3n<5d%RO#P!Zo2|uS@R>94e|pU~ z>}Obq{R#i1?=+z+!N^9_>2o88anP@3tnq6b^ZY(Krkbm-1I8BrzA@i-j5hvVBj`Uf z9(%8i8=f)_d4=>@{ta5=wL(Yr$NYXvbi<#F+R{7d4h`ZCtQr=&YqODWz~!_mZl4&0 zztOs>^%83)<3`k4)kXW&Tca=-YRm_oo|@?k&uHg^`Nnck5VZy`Q7JGByQ)4psh*IX zs)spA?b2?e56th?Ewi*bVy0CK%ssNXIanr{#pM-pM{FQ#wbE;na7iDLU{)0&Gq=cM zzTp+jyS%lzRns;$a>Ja&$CCV<;tM)v>dTPUQ};y2=`o|7W|U>2Qy`(qK=}QDL0_x# zw3!;Fb#QlSQ9T`SKwM@y#CSeSs|udz?qE+gKz^n-<#<{^>DdwWyFXM7^QWkmes9&n zuc*5D#q{Ty)DpkGI_(cvkNrdHrJo4y`*px(e>G_5zXu6^Q;7VX@UvIQc;Zblu6fdk zdNolue1!K&6;FNhBTrd}b)8#>zA^sIYlOCYr-!0W+PV2V@`H=U}{N}M{7T(Ex!Xi3` z9j^CIKt|AQdY(Bep6^dVh5cK`2d}b`>K%X|y>c+CzX^2rF}UFORNv@HlJm5@?7)5( z1`mn(ybmYhj#dITWede6dPRIkV_4-d23mzk@f?MADx% zBU4GzBRLh^5%~qy}2H|Ah*C)V#AiCzNQ+ifTM6o@20bj z1E>&cfX<*-#sECdkT{32nw)`o%_(q{*&VJii@~jC5FRi;fF0&RFxS-cWahu>YqOmy zVEQthHzfw#1IyHw^1EX}WttS5uK4e>r?yM%d zr8PFg=mcDe+Pdr2lf2PqzVJ8bGiV0M#J(qh7b34XA_v4vyhT%~m#B|;009)8IH#2Oc7Cz)`XjY$M$?K_eT8;ZtfV?yf50%<79~z??*@UXMzu8$`x!sR)>T5Io1=XNs(Q{u%m^yPD<$r=J{gv>7pGQxC zZ3W$EHgKA*QQ27*Jq5Kz#%b;Ka!u68E`Aa}i{|3Ks3T(9Rmu^SL|AIaBsoWz^1A+7 zJ{gj2Wg|IKE|h&`P<4~Ps$#M_cq$ywQ*74}T3Mqczh!J-El_oK7d@qw@ow4!Po}@% z<+Lk~(MotZ3*(BKLj9PZMN`Eg?L@odfA6lRx`{Tb+i0hHf#$1J)KOPN3aLE!k<^aA zG7p|Dlkft0TK5~;AfWy+n(Jx1Ybpji>v%dBED3MH+hB|_7okb&bDH`PS917ouW7RPb90ta;WMk zv#R;>vD_igXsYoVxm2H6<76M%Q{TJqWOscZ2kIDWtgIuu$|16ZJSty_9BQ^$r!wd| z`*=PT+-3Jc4psmTreonF{}LRotC&Uns)p}%Fk)U^ql%x~_)DK_BWS#li{&t`vagI^ zcr&AnSYX@~pN!%%D{3e^qdIaqsv>WpVmfxpENkMZ_zr&(O)-&~a9#NTt(V`U^vX3> zs1-(aP|%2iYj8gt1_u~LVE}#68Q&A|99;lK@o_K=9|UXgday(9#G7zAuuS_{ZNR71 zVLVzr#5r^&^LLp*O3O;*h!{;OiT!&11!e)A^a-3EWFW33#KAr^b@I{L8+$tyz$cmzlY$-f3NbD2ZCqz}eaT1RBpwtgC}Y5haErFHZ0Tx-WLx3!GhwM~nEYI{Ha*miwfrMhF> zv%0+ebM=<;N1is1Dn2N#;*-Un6s^@&%ZI9am51?MV(scTWq1A~(uUPz;%U{}t7r)8YDi>$lm6x&}xFl~Wepz{dv3)ie0a$K?&L zkQ+VHc0j|}w)Go!;Jy7%s&gyH6hE;3`BkM;Y^=Q&D}(d- zl^yf3l`ZmTDr@9>R_0|t+FhnO17}PEjy|FIBP3bWRDjc zjL)*k`=eBdQk!_2^nr&Byp?t>u=lmbigWB$h*R}1#n@!uqUc4W5arLk` zqk2}{uQ)%xRE&-d<$iIuazMPZe5)K+9$XHKUl+&6-HPYq=X|c^pz6TT)V5i8pzQ?S zFTFn8#0tw7ZDkly9iH7-Js_*_mhZ*Ige;Vso>+cU z=~K?BJW@1PwlBt1rdFS?JYGG$@*phux;ix%g!tRkgZwXnY9%E&XyO|Y>jfa{Lu2s{L1p3{4peatsGqWsNB8sS$QVq&6UT? z`zsfg*H(5ZPp;(Uc9jo`&Xr5}A1{0HNrJ74WxUaH0W;vWvV)5+S^2spJXY)zJ}-uc zj8AMIQLY`HDo630e&?`P+$vlYw+WBNHN$6ol51Z4TWlW=h+SEQS}pvp92(|v*SW>U zp=+^k_@sJzxUc$XxP#BfJXM{~r(RpbfTC}9da-Brc5!#st6Z8L!kcmzm5=7kz4IMQ zJ~YjzP+utcE^nR-Hdd?owbkkQF4e#1+f+}@58{c}Bh`i3it20GX~kn%Q9P2}U%r#= z7$;@pW0~y}y5=wNe}7{bnEyN*o*$O2ogd8_?!npYZ0GESY`yG+tY_9fE5akJLu?bW z?A_QW+b@pHVtH8hEdR^tta5y|f4Oe{oAR>!jPkqus&ZK6hVs{y^U6O}epm8tez~l& zW4R8W<=q+2ynVyV#kLKX7V9<~QmoprN-@4Ny?RCE%WA*M>(wXoF}xx2L$zyOt$v#I z)9#go7n~B9oggM!P&dz(h$ot!tgjD z9u#+pm&F&$cjM+|j9(Pn@y5g@;o#!mVaK8^>{^V>jswdZi$7&w7UQxZP_eoSmvIXC8&tKyve>iA54PdqSxF3!x} zi|1$G#n#Xo&kG~M%y%%5Ab?+(t9qH;;~-O5?jGb^XyTQ8`#@}BrB z`Tf<~@|UZ}=l>y!HdeR6%C^l~vfq|xXE&AIvyaOM_?*s= zuv2^(JlBek#iz=-{LjOop(u_HUln(Tmy7pV<((2<<#Uvu7Q?ei#c|n+;@+%7IUk;` z$ETxzoByY{Fu$^RBHyuiKX0ne&2O!;e!@Edv)g{iUuyeLet+BD{P&n+@-Ny(lLCDET5(#oIiI4v0WD8rTRk3~9T?BZ&WdMe*T%E57viqjS8?^M zUHB#p4L61D!dBtvFggA)oEaYtz2ZmV*>Yw$p&Z26cERRv$a<9T;hB2pi;Mm8xyAkY z3@~ltefkdNO?ah`D!t43m4RhjrGHsz7*x)y^ebPhbT7}TbS_uJ(%#4$%9C0D9GnMu zzqH`Lz~cv|7w2Znic7QJ^@p~sr)K?t6Y#h zTy|&Wb?tm)xnn-R*gJo)I5FS5I3sVaUYtK!y(~Y!dLHjs{4PJax_^E}b!7gJ>Y%)( zn&^FrWvYMDASv zhtGu!sf;UrU3sp!qHKYTbZNt*T@Uz zR&UM+70>2J7GLroj3aoDsB|eetL#^ftT4CCmzJ;Ro5mCIT%Gc};=_2V?XogXz)Rf} z4i9^V3q${KUziP^@5Tk;o;WDGG#(C?cVs)oaakW$)u-`4Y5!GTn_pMHi>8|LL0HcB z#om>>kn{*V*V@HNe2V`_q}z$v#s-xassk&3tFFSQfm`!$t4nh*%wzTWd?4R%uyrvy zKd3k)KegB?zqS~bKUXZwW*0AK8{(zTEqCJkQJO=$_*&RKo{4^kg*)SC@sW68yf1DM z?})LyKE6}l8vn}5nY4rfM{&_<&i}>_Oc1ZDNc3JTjpCbP} zn^P>nXLrvJD!0o2TJD^GSNl zYy6+buaG^4!}!jZ_2K8z^7!oA@-Nvl<-f72Ml5P*z7wBM9|_~TleH`;ZpptZ9?jo` zqt6!)<&PDA&hNt)+*WLjzg>k<%*$>l-p_6$=HHBWx~|wiyS&(xncS+`O-0D=DQ4rp zCxlOn_d+Nif~4DSMl?bPfEe)G3B2rr-V<-o$-11W?z+U+2`fn`Nu@pcgo4wYPZVY$^n%Z z%Knu%cvIlha(+Iwd@Y|>UZ1y>hw-_(opRm_=06;7oL|Bd@7v=x`D<~%{G)hW{$sp2 zUmmZ{`-Cfb{(WM;b=W!o6m{Q$xu!y&l;WVK}+XR@vaN zb2d5thD`9d?Cf}2wgd0Xc4M1XUYh;0JU6?$JTLn_nc=U>)3UY8Q?mB>+@-~l#GSpf zvBf6YE972J^C_%H!0UlxM!35e7p`QkFdB(H(29}X;+#GA^`LFu8G$BW}go{nw@jyr?jD7d*se7WpOWbG86XT|qPK3Del z@)z;-^8EO5`F{Mq91_?3X@8d8}Xd)z-*OpT(*EX z{7O7GyM-re$FaX#JUv@49+`EF`w~;O$i|f;vro&uNFB0Q%Es_w`CWLpd_O!>z8fB7 zd$jyCTwi_}E-J@`L(8#Y=W%x2?Cl6bJ_4FvWBPSb5 z_Pt7W4cog!>}t7cwoV+L9U8aDE{?wfp=uP-u$hkd>T=t^Y3T9FEWWhrP1( z!*1E`Vax28ux|E8So%zu7bb>}LrJ05$4H^6mjHU&TW&p15)6IO64-wd%A z*1_jD^1gAiymMSPuSBxKSY#c@;~V&tVkJJ8wTn+>A>NYdKdk;xUXZ=X_E>pxb``w- zeR(u7|IqB!{9UxH$~(fo<;1XOIV9Vm z+$S4_HLZ??^(-$Uc3sMx_5$*x)3V0m;B0EK3+1L*+qz&oA{$w*nH@m(aZ$N3UT>R> zXY|>CxHoZq&+IbreU9zNxLy{p>|tS0wqxj&ofz`$ny@%L#QPDihOffd@OoGn?hc)^ zE5mx(!Px$0;ixRe3-G#kWcS3Uv(fS2**3)d{_)3bZaJMSw=sK>oam{tIeU(||I6i^ z?6q<%e0?|jqEN|O3x^d3AeLm z_>Xc8-X+c9=-fCsegc+H$3x;x@wf5(cvd_6}$|d2ha#VI>c~o{;c^#U(BRdhvjwzqbjwqjoj}K=1z}sJz z7iYhK!+Vz}fa9^*3CzzfD)-O+QvND?p6zYsz;h@&k}Yd$vihPOG^yCOUt z7lsemzKOHLoVbXY$!zkdDa8HH!q(x%@N2$F<_zAKxiM@I9w38#iA?s3a6z2R451pj zlUGeC*UnzYN*<@Dhs%SQ9Ue(u^=mLb0vrz}x7>$W_w-@eiSYd?0k;(`QSu`vutZ z4{(j=sM%*k+)vBjlTnC;1+_e}`^S-o7DwvRpm8k{stW?Dk~%_j}^iwP^T0qEzfi=RRanrCv+%>FCj@^qp zLcBaw%ZEa9`4ay0Yqq(ZYi9P4@qR^@Y&H0`cI?MCG#kz~f^~z{cxPl_+$!rGcgXtw zv<-?oXT#v-R&kf?S1{v@I4rv{_Q;-yi^G57M5Or-pA>w7%=5vpMYuKW9sU%K4cGAg z&gJ2c;oNXL%zPmHHas2nBl>R_UI|0Oo1u-_-#2j_pEH~nu8$3Te@Fjp@3qfa#n|KU}koGwnw}+JDfOnGIPq`(=);JD6C@N_;J`e{(}{U8+ni9 zg3wYP#e1#?g~hx{REfKX-f@4}bufA8vEkHsc(@jX9_90m{{qW*dC%;Nn1`?9H)K?g z#7XgtIGvcaAP$KwF|ZOegE;?Lxn+2z+$;R8{2g=F3$g!uIevzW?33_yIX>`xKww*j z)!^1}q*^C-0JCn{Al74g#evxMYIy%a#H7BpxRk|Jvd*y+p016V+;sHzMK~nB$h`RB za1CsGjPDeBJ)RLJF$~vH(lx_R4W$4AcdMe-P@fc%0 zJstrTr?Wb6HC%fvypIq3S2-2Q3+%IR_E9+)?>#DO#hVYnYyT|%Ec+$1v%Rs917XDO zNVIdD7S@ZOg&y&hFt>a(d=5unC~pc+lz$0#m$#A^+y@GehflEmIk2l+{Cn7h@8H-w zJ`_%hH{*BC=JPLmAx}TvoObY6}JGhy}<5hw)5!e zPjK}~sx5{V9DJCkpXyNb25Tllor z-9-Gm$oOxC!+!}!FsoWO+!>nrJkJNbnRIV_m9c#iejC3>TZ>sIjNxE>>*2g%c?=jH zkEb~mOF0!wIT`EuHJ*HLJo)CaJ(4$ulDug;cK>>L51+8R1fP0*xUxKq+Y>Ngg}weUoQx%$7>^4_$9<4;%kWEVcI(&!c9gLney{_P zq>)bzOfBDL*7HXEg4yJk<;(Hw@+Bho-}qj>N8=J^MJ+rxTv6TvGB?Dw@(M6LD|U@1 zf$8DA8@~@xf48`I+=*OZC(zxNtYG{26x*9{_N(}-I3*q(7sq2`D_KGw&WXq$`w|(3 zg+Iql*nZ9k4u&NsFKK)#11^YE>m!Y{#a?`%`D%ALcm*+JnK z+39?b=fz=@?2fPw+2*?0lVQW`1!hQ(hHbMasQ)l^{)h6euzmK|uo?IcV;0pVJ1;cy z`9d;uJnMNd_R?@BUg7|}@8;q9uqJ1^!QqUEwve@!S@9bD+@-8^pB-L_C*lJS!}spQ zC)76y`!kY_Vu!E_o^NUSEjYd#-!1>etmlcy|3;0s^Uc+_GgH3>{BCFFeph)FPaysn zZ)3ZzyfR(}o)?uDkb#~NFE4)=uP=|G&SCLyNUyTbTz2a)Q5a4+BQb}?`I9vhwsI}pd#2~UJ} z;qlNI?+jz%>l^XP@GzL(9FKv!dywmF5srivzrxe)z_Q+EjAUKxcS!u6ob#L5D}EmP zvRc<6{s&AxizTzkqWq9d^Mg2-@@uxw*?$`zzghl+S?H7T4d$rtmJh~p=%A6UbG$K* zzz^(B9(8QIE?!G!b#J^P{v%$`r}nQVv%Lwc_$wLL?eu&rTD>lg3$?#X9jNwSK{^P;&G*zmKUh6P#(pQq_i^pE_|Nh$;CLN;yoB##xR~wq_*QuyZJZq^ zmlww6<>mO2tC^?X#C+f`^8d$ct1Ite{Xc-_a`e`nC_5BO+AJ)^YRY(ED6pdTc(ium z7A);Cw)a>u`XThi_pOePTsv%@{VeQ}?G%2K9RNpv6Ha4>{)g=Mlvjk&*^S}o?DlYI zc5gUY?igps4R|6mgox22 z{u^KT0{-#o*jzq>uY3SM`Dks+dBV_S zv#NIup7Q$mYj}A+_5Knch|k1F>EQ+Ps(-OI{T4p+L-;o~u7f99H%yPC@JbsoW7#US z@J*Q2_{$K%paMu+2R~x9rz^&(n#a4_J1~E@ZxW zC9&pa{NZgpZMd6x(JkC_eRu)OeI%TNC7*;hJQ~anBJ9pF`SzGK!a&W4%JeeJ%b4uk`?k?bRjQjPsXfhybPqKgV_&!Bj*?K5Ai+ld=+e;AV0c? z71HbCfvlMv8b>p`KQ11@nWNCa>1-Dg*KZ*9+{=|0*xuvZIBHBK*7HeTTK^p${4{zy zow>khW?rXbMWgZVr^oflQnuyVF0kMr@`2yLh||ae_?B5l@FE%bhvWf2lG!wpYjtMC z{h1AIPDc52wqLRB7w#d8zXzo5gO~SG-iaOG&iNa|uHgI&qWTW-beC`xtI_*&eHXC* z8ECJCWeniX?s%OFZ}_*7n=a*BMQ5^2iEo4DKfv-iw0$4Z^JX}EHE*q-3znxN?XfWD zFy`g^k;m>1clTgzd)IITCZ#)_*VTy_3B=$@p)@?r$e&`YW;LRx*oQ@t?Od*S|S#07tiE7A6nR|J(z+ zv*MxPc|6|!q;L%Q9m#y>ka$V>4Qx1?`Os+idOq3VHSu;vatBs;UyZ+CF<+Vkdm^** zZg91KcrFYMPw}+zan?p2Ap^RDxzeA*Kq5{*aO?`&ox{!{$JQG-(-AMzJ1l4RJf9qB zCK62pmucAebR?L~d~#B4`=9V-ya!9UoB22YM}?X7U%~Pma?+EDqWgl~?u=+F7_l`Y z+yW1`LtG7iFoZe6aIhW*ZX?NUc}|13y9;Z5g#I4n_zBiV?#GHB!Y|(zm&V)T9K7jx zJiu5``xrdm0o^z74lje}OL&o&cuV1x7}@y$uk`jdcz%QzdJimNFUQA{QJ>80_FOiy zZlrw) zVxb3O^M}F36XFa!LxmwtzZOo~T>%`vdzT&(LH%FB`dGV+1T*_63l z41>;R#AlPqoCUwmf?2-@oAX)iI3Jt8nw5|1i92`J?EDa{_L$oCIQIN7KJ`8#(M@bu zkiCz_{tv@*{sL>?ApA0{!Fp6Dj`OfPcpk)d09nY9p(!4P$Nnuno`}YdXI1cc`~dSY zSTG+K|_4_dH zmG~OmdlSz6o3n56cFez7FMTsUOZgnk{2S=0=Bu?i{)h2x?tYh6-hrnd;Ya@ilRrZv zW59N7Y(yW+&_^UI?Gz^BODB_0O~V2vVhvM~bOH>RNDTWSZjRsFoO7eVdlU>B2`|?t zQjEk}*CR%41iwaMyIW!3J7ed&W6=k)9Skpj!*&GQ(c}vUlCAHH4t8YQlE^a>t6u|# z_JP|y_}hTLXb6MYM&L(>;~myRbL&!W1m+uZeiXQG2*w+t-Hpgr)`JZrS-Tn$#(?RE zM1v2>^WOy55AbqtF(>_ysPQp;{hU#cBPM+hyT)@g8B8W}Wd`_6q1Fsg)VXP(H;p>N zXg1i)f!lMrx&Zym$J&>G+yb_x9L=rm>->_qkiUy~CeXs){bj1Gw=ST(a0v>~9aMJJoWZ9%Pigh&Dsv;ZP9Wfc=fw zHX*L_^pX87L1+UI8$o+&u@884=iYAQpL)LEg`PVhK_}YnjF;`g-_Bg^%GQbBj%*eB zH^6ij3N6z+0 z*%^NI1f%|-HUv&+tRwMmBN_e1wQ_ULj>0o;0k&HZi?;@WE!cKo%s;2C-5BAXl>5@! z{uC%l*SZ)Z5*P^FY;bd3t$+6`X$lk=b8^L1%-fSjJ;{S3| zP6C}N?9bruJoXzovlzQt2yRQ@Q6t-8@SBM>&cP-p)-ZgDt1ofK^VIx1?L0|)Ph*jf zvHvLE@d>ua$xff;&KI%RmtgGMc*>7JZw%!`>dvfL@Fa9L38qaaE1Jz4Gc(8y=EJz@ z`0UxN`AuSfD&^$bHlTKX227mCwghWmh7AR<3oxn!`Fs~}>xzYT1-l-U9pGVS&R4)R zC*F`zQ+IQ49Yx(uz;Z({90_9UQDX$m9Rbp7z}D4Z>j1W%Al`+HsU5zdjk!fL{$(*e z&&OitVzIN3OcG8fN>3)EoJfS8%=PhD_C&1wJL-Q+`7Py_ocoe2$QD14{Q=BhIB>T2It0u8{f4Lu9LuSDw>(hHkaesY>T+Nm0ByfqXXWr zBR%#Y>hvZ8^`WQ!#K!^nmjT4c!9@0ftO~D&ujwD&0qYOgz5xI6)SW`P06i?>-YWa8 zY#CS-+*5FW3%SS=_7|dqIiN6~ykrg|UdqT;;LAFJ<|<&wC&gj-AS}Eu4DJPnJz#F7 zw(W=S-G^-_TG^UAH=u#o480%_WivI%@8?KFJ$IQGY~{}Gv#wh!U+$CO`lemvzY zq+Z7LHb&3@I$eq9?ZIXhW-$S*IukFN!Ei+_zuA~kZO*nO+g6Nt8<5%t|F#|2ZdHp^ ztC2UY4Z0g(@tcA4X6R=NY<^Q(-h^7~A?a|oK|g7)C%y9z)7h5c+m}!-LBe@pG#4#T zL&Fon?mIB$EjzXmuwfY6x~%Y#v9W#5@h5104A_6hh`-?eG0aduCuV#B`^JFnXW*u% zAH3!A)8DUQ^mbUMym)u`(F;7fGLDXTufWKfSz}ntHWO}5 zWt&J|JpqPHLd(-AXCdiQ_FE})yk=Lp)|(Ocqm7|pGKe;YVAq4es6SqI0Lb(KC2xxM z8-dpPTpPhQoVo+4+mGIR(Ly)Qv_~t7Y6U%1!Da;*HKWZHXme>TJ~n`1&bb0>t+FkL zVNEcm3Fa(hvEg+Tdpk8B{YFR5KB5DYK;(qR}$A+lDWw;v3q*#ZFjEj~d5T;E@^_RTYgDY|UV` z5PP3jv+urO+L_FVZ)bLm$2HtoG zHaHNr4h)~d_IIfN2KT;Va}9ZrwK7?C#NB78^GaBsyHs~pQ)v{AQ-aycVh&VFkRw}CagZx7eI z!RcQ3m{o~pgDD4N2Wt}1R%aW6&l!RR_NVp$wpD4Z52*L1>_rbf;7!lk7CCMMvx2g@ zw)F%PdE@S6)`~Tq7*$Dz5Q*?jV7LsvE+8|V$MI~u!YsVPEPTTpyzE?XnGaG6L2U_) z)3yTSmvUDdXO+7(<4YD}Elc3_LJ(Y7^T*?9Zz}$IM$Nva($iFWoQ?*jAkB27nL+%R z0Sg+zb}m~p8gBw?*>41+21eVSQFmd)UGNh4$AB53G3{|uSBy=y+KJFE~(dvUc7c=bhdec{Neu)8JH13(j{Y%h68=H99 zj;#YS_= zF2hcnYPP)*=htC>eOi^Ruk};82Bpr+7mVQiQ1;iP*TIZ*7$Y6bHjJK!(yP3;GKb-e zd?+K=v2v*)Tw9HL{kXpuTQ{UvW}l&l7BJJMoTLd1mr`p5T3J!^5`!805U|($YbaV8 z$k+!_uU~DOg&wA%lW*9*q~#B3;{!%1Kky!HeZaZT*}mlXN3KofTqFC-h;S>|FX^{n zU-7>M>=q-@>>Be{;LYWKmyw4pBezw?ya28*fVXq;0CV8-EZ92-M$41T;O?nNF_m7X zGv4Wpdj>en0%L9Sz;HfgBj=Q3E&-n<_=OhAMPSncR*jU4z<3^YW>a@Qx#d*yC;8NA zZ1eHC^H{@aBwJ`@T z!G1j2{T}}R06)J6nQ^f1TlhT|K8|7g99%!Gl`ZTq2iL{mycj<)7bIu%I|Z~S69vb? z=<#T146TlXw_m`uZy3Q>NboJ&cqID~sU{=kY-S6yDI06pt_RnIt?*t0oYsPa!@ym- zScm-$(9K40bTjm{8GPM}{Vl_=$O(p9EJYbN*}2eFc9%WB+5yk2wDy>U;!yJ_f_F z@bYs;{2jdfo^3o>P6f+}HHOI}mgHQ4_S(R#WNU+y$`e*FvuNdbDcdr9>|*@s0z7FW zzcblWB%1>AGhp~saGgTynw3pO(m8Ciz;*#vw*U?57|sWS_n&a6ci-Pe`+9l*2;ICrVVy$Ln!JE4d6H64tvv9TR(3-<_; zO(3}(R2PHq5)fa=wt!mlzVnf0J}oSy<@rdlnBEprYNpV_wgd@VsiSf^Ju4?$N}Wc^ z#u{UKqZ7@222-xX=+%Bh^6fMnkx?KhNPg85ja zRw>K;no*9S-Z)C_kEg!osXu_kcj#yWXo#N^VBQaS%kfzDk8o7+Un>&Iq$h)*=5NX& z=J9u4&96?UHt*t~rFLx6R&Q)qJXI_i!u}fID*rhQ?D$kV`^(^I3z)S~ubFeo9G6jd z1?Lp=n&EH@m?`!Z@KGyvUOCtp6tvPX5-di7)iCUR2y7h4+(CJkGKx;HRNg?@hO>yi z_*D6WzW7kS^$+jcLXQRKlwr&M8<9k_+nH=ru(pYe;ydsf4|Zc~m~{m|VcHQ7*A?HO zvKv@-X6uTl>k77=sV{6hfoErU+5ivR(_R5?@&(J_Vl$jvNI4$_=TOe#?=%pd3Ci-R z(_rpQ?wCdob7*ZQ)-Vt0=G5>UhSt|a>+7(M08{0w@&h9nfoxnW0lKc(G>j3gTjS&` z?0pWLoW-nmK2L+@kozy?$1oN4!r*aP3HoooKlOQguO!4veBRn05q@&NZyQJE%J;(0qEr!orptVnA)Y=~eR;bjR|+u&gpn_kX2&4rp_$x_Ou8e2U7 zQjA(iyjp~fF96%c%(>=+-!lB^Jh0U>@C9JK6#HKWkF~y{IhyAQgJ@rweQ)~I+G*z+ zhC)*7t?em!udRk>S0oaqd=oX}aSq165yjFLVsVXdN^g!TQcT2-CooP$QykHqNua%q@ zxZ2E_75r-c-G)TX^w>skO<=0IdK37`vQ#bxJK6j~G`JAWF5&vTTAfwFtq<3grR!SX z8s72=%70@mVy}+I)~M;mzEeJQ09?~Ns~4E{1~aWlcZQD@n3}T%&bHAiZ4xE|IrkFDg{3mhl2ll5@N9%jj81WR&&0zF% zIGzvo3(?0iFkA+f!bYoCZJ?!u)>edif^JuQY8Og9Va?gsY^)7UwbnG%pWge{w#AeSYSQ*b zaz#k3Y;|Dk3Wj+NqZyQwV9O-9`vc{7Y~$hZ*I?!R(`zmhK;k>jO$42(ATmJL&C~~e93`<6;nPkavQDakoxY)mTy#xHy6Q{0h%8`0fb|)UK0)~CSwl@(- z^Zvfz+K1nMwZGlCTbQ=5#il;+v>(0pMuPrG(5r@}c(|BNv#>?rr))&|(^90@iq~Sc zMR06B7|nw@Ga2brw#hKb`QpNz>mqRVa|p$r*`Vp?4#IRQ zM_Ln`2F}yDL*>+3w9?j{AXKfBp^t*FpSUjo(3FKA3F~S9Dd#4xp}{ zwP+2qCz@D=p7h*BnHB#c25#$VPz8BP{3HL;ky3vH8s%e|9Py<|oLNyDOBLK&L8KY% zni=mRM%@Ve8rh%4c|FV1>}OW3oQV#mv(2tyCw!KJlQPaWYP5mf3d)jmt<;l^TT^pt zylkR9`2w$UYo&V$^%sHXa%5SKS1IrXT2;_$f^x-6<{7jewHm02`Tf95{M56E zo_L*}ScrUO7r5xGcrjX6KB_gkmRckzkv>po1>;-6_?Fgwm%x_=j8BZ4S3^x}QF`{J zBXLnU&jE4SwxW*wrLfYfNhABSXuT0^+*mQw| znzwhs(uH9s=INcV{tm2tcLLiE%;SZzaMdiT9rXj7e5m4*uxue7H-Vkjr4)A-5Kk6j zMU8A)ms-HKgi$PJL`|?q@wSP-io8p}rUjgoNov(|0baEcpVvsHKA#MJ9#+19)scmi z3(4x2bAAbRlqs}PPo7w7A?<53hbiNS9m8CJge|b`L|+oD_*skayi&7qg3`TPpfAKicsWh+~ibG+P7%?cw6Fh^NUWISC! zEfNE|z*glq!cE?_J!9_#!VO^Dk$tTpH-NF`IT0)Z_0sC8j@z(hmCAZE>PKw49c^m8 zv?G1wwAm4@vK)Ka~q8XTwiLw)xbVL#bzosyF{9{Pavx*HkW`-A2mA z^sS6oGAJI&f3Dyj$)-0Ga{N~g9_<-}Hq8MvmsYgWdk$UMdV*gUj)jAxSjlyH3O#WW zyPM&Y*5#YA+ZDuS#cSEH)+n`KprbbS18qj?WwfK`m1?(rt<5gAeZ5m5uU;UBo@Fkl zEJ3N6vRY$8N7@wH6^@rPKJ71O{CdB^?>N|}H8C3gNI7+ZMJN^@Oe3%-JG(t{|D>rJ^VQV3xLpYNYL) zGH1++v<>`0d82GbPZk>RsKT%UOFOY?x1LW3LzP`>$69?7uBy|ucCYL{qrTpuQD!Hp^hT1_^Mt3ECPub0GI=nMppCJM z72<_6D)HHj5!Pa*?$c9Fu~ukCFjUzFhRq-;Y+E?i-{qXsJ5kb)=29za8d3YwQkCCU z_H@j@-s87Q5BjU$Hd@x-f>QofKlZVDrXkzXsKit~*A%vXVk6{~Z>iK1a?Q`hXw}zR zM?0>#uJ-jb(kpX%TdExh%A+Xjtkm?PwzQI`(z?(aL3&msYmxTbb4Lb_dSgjAQq=58 zG8VNF=*g!LRjHgcP^y+jDc>e?jZ<-^0#ZUvh{;z-3qoDoRvo=_rgK_%QoBN4-pA`tD)~pk-vzSt*Et9`{HMK-ODh+A4a5(kB${HZY2eTv>oC^a|J zJ@PVsJ}R%$9*HEG{iQ}GY5mS$M{ugtSk+MDk8&y5o3Rv+TvM1jPT4E!iqQ0WoVaFd z6{?C{Vw&0#@>z{-;;1ZGxth?^I}t)t8q~4uL0XhO*k)zV;+m1P$JE#qONEo}6P7|) z$jT0dweZqAgu>5U6!OAT++1F})(TqMlie#KInR~96|%~5g|sYOnvgza-9l5+$Y*ON zEJ?*Z*^8pOyjy$DDL?8!J>@lutKF!p`0TjdMk&vyV|h*IJe^>dJ*v*iBPzNi&T3!0 zRgPffjkC^*^+MZH1Zrp%R8m%Jv9cXfdtde>zo@A0Cr#poB8#3nX@n_n5dz|pN^wjv z*}PQg+*SFJc&QnJ5Y!x8$3j{DSGs8Bs+cR^r<$^Op9@IfIH>GMkwtb>MRM7*@)G-f zy}zc2qxU;JbE=Xz3S;G##;kfW$3QV#*ov{vxQwu(mE)E0 zm1htaRqC0(yrr@sy~)#pH1dU7trrWHA-STFu=Q*{y;mzAnS-Bvn{r6yGMZmIk6Z{6 zUYXKcz?$diSXh=dT)KnH`wyK zb6z<1;-0RQ`V5HP0qI3MTL10IsQOTM70wCYUW{J&YL26vQSUm7r_OtXqa(gE0(%5S z8Tk--0&PN2(Mj=5nijUgRUBNwCjW2zG=rBNx2y3_n2CFy)q4)898nkvE9K!!KtWi_ zVi&bJI=?X^`xisRRh63K zDI*f+gtOnRPrg9c#6{0zZ{ajN%35`imS@q#YyG&o?$s+8BsA)C@S(9U1f=i zTH3s(s2s<5t2B4z6BK7V)NoatZDKU?rSb{F(zdVFD6K$?VOrNvKB-kI&3%;f=q)nk z;{_{F&JN{sb-&mt{_B0-lv6pkbfzW0AiwIhS!q-nmsH9{B&DLMGhuO9xr%&(=FQ@; z=X{P9icvcD8j5|buvgCG`M>ZK&o$SPj)bSMcGmA4ODs%iCZ>87S+U=^%Br+ZYiz|~ zODTyZq4=oMSjzf@o7Q(7t5hmF>j|IYyl|I2i_bbQrU`rT&~Z#W(|Jc6MR0?0^l*$RUo~}rtc&53w zt_x%N32nkw%u{^w?8>+)hjkV!|0(t=?-k05lk&QfT$Uoqbg!iHikN(q@+Rd1js(uH z)Vu6omZqFQBa&Yb<|>7T<}n(r@+h^T=&kJE2#JScmk|@fMvR-NFVCrrO%Y0^*s0Qc zLflt8#}!xQuM|biaY?ND;)WuFR`)ytXEhqDX8cA%a}^<>*?|0pe4u7ZDrL{AEAK3n zoF5rkofD?=qSAo9skC7apzKR`sSQb_^TJha7(4YS4hu(NpW>NI;i^nVI0+TuYc7gQ z(ueR9&SIppcKJi)PSTq2mL^m>#;dM0q8iQtlwpXW^5n+P`GB;kdz_z2)9T&XpFNn` zmcP|}Pw0u`!rE*R$0U_vk8?6vvu#zmsF77IMR(8f%|*2$Z=rL_g5|NbuP5=+ju`K^ zprujuAnhny7KXxFr88+^YHY=4do4+2ehMv()-g_qYF6!ew`|w5AbC?EB-YxNeV5RZ zH`Y1j^oi;6wz^X-D=K<6uiCN%b5a;-U)q(mh})j62xoCa5(-UQl`xU-5NkC;&u`=n z%~&HZk11?C3)Q`1v@sF)bVd=-442l#S@kBIWdG)%vSneUdYY98XXB|JjcF>yZh0@` zAUz00=|$G8{>)cl=P2zJ3xMHAXEb)PTQ!7{_Jp1GWaIh~7v%x;t8?nZt4#K>V!dYi zl0}}~ZD~%W-sQ0@mD*A~lPxNyNj{BG_GNz{u9@q~3dDJFR5IFY%6mvJ!r6E`AC>Jp z&I=3cNqDL!V=U?PV=W3J)e^2cul7_=mZ%nFY0{>olyu^;u~ltxO6-vh>Z}nd8`|aUBC9L@}mB6f3inuNMq1l&TFg(XX;|O z&I=pui=C2Gqf`z1WpPn>N&@2{Y}Kom2YTs;?){VV%EJ@X)N1z^L zmBv){%tz^3+7%M2DW<4L>0ZaWE7j5LLM_TCDvn7OuVzUfLd^FHIcZMvDe{Sj`c=ES zLwTxtm8a4fdq`dXFBQ?XmMbiaM6Y)pB8Gi1jfA)&ZrFC+Y9ZPL6LrS>%vwV^1WR^{F8(=-Ru zS+UIC&n&Yot4&9KU9*i!bK2Jx;p^5Cj?OcMqj;v$Bh=TV=vh z?TC%?r@~GCQuhcAjY^nEAI3QOH?^YiDNB`(6?1eXJjEH+ldhCS2w%1CQ7bFfb@N~N z$cB^+Ck7=em9*+vj1g}Ysb&2-R^P^0oYYyNs(yr*kd-X&2`xo~oyj=&Dfhv97rVm6Au} zQE7&!o`jXI+cs?x8i87qhQ+`Cwj6Ol+EgTwHieEXQz#^hRX=8^#%IRKi>W=W9~oOm zCY_hARcfS)>pFIPm(3=7M<^tf?-inwT$Um1>UJ%OEVcE}fM1b593kY@#2xWl7B0zU zzw(mW)3M`*&I(PTCBEA4D$*EBT~$x2Cv3GRZ0#FVTVr$&ws+N2PvVnjQ|e7p8ef;P zI5A1=5m$wRk6j8Q#e3CI7AdjMoL`Q6U0JUVk>prtrSju-8TVW~| z>t5k5UYeWoJhmQtAhl$RQ?#HO$6|*$DX-^!BVeDJM(vSll*ZWX5}vX|Bc;1_U1yWU z%ZmuLI_v8m#JrWX?$H(_95q7g!z*W!R9e;u%~jzqzN&AHPCw?M?pICWtNKDo$J&e( zyPVe<{ixKDSRf6E3DSo~U|*q@)xNH)wtFxaUB|OJG2B_7qp8|89>z_*>Dbb#J!wZ0 z>a2RUtQxr_^5{GUdk)>NI&Q^$R2v$rII16eZ!tkV$ePrj`6y(>OSNtflYFc0lq3l= zm%>Xw(x3WK9ZP0*s=m?HdG%yZq4Uo3#eB=MGB0(HjwPe(DNd=L@RTnSPvt*kg()Ix z+9b4IU%R>W|QuD_7(-`$5RHO;lkj%!!{1SGORW>18R~%F%brz~) zYfpWuFUcw1GTA9yASthjSB^zHI9-Yjo5z2Xc|8u?JUYH)?bau(ccKy z^IbI(ysMnoH_MVePeE^q*Y0$`sRs_#2?wTXE2(Ril4S@ z*{>suFwl?glua8;^<&F6eyU;1S1nx?YVJ!tNnYV69vCsi=l;la}QQfE7l}6-yC7to}eW@MaZxoHABvc>zv7K1+sa0Rs zUphwqgtCxvJLZ-8lxLKDil@e2csLqmn^4i7nXFNZ<6?obV_B72(N*8&Qmy%Z zqbn_|PkC;0QQlG9Q_HHYzuK4mS}Gr<5sABIrsPh0wjb+8wGx_=G5we~zDwtfr!qF_&82v%9)yc~GN09^e?0p7sO7y< z&ZIVdXTscAYE06yJg~BUVePzGeK=Ao*Rr29vhop*y5?2#9SI5brP0-otu>?OtR^wW zXj_&#Hs+gjll)QAL&C<~(71({F?Gw*kNelX>c`xYeiK%fP@~m+(d#bKomw($(_NO+ zE$WISlm3mZ^Jr(*DH{>y%4poWGgG&sUL}G4CUne`blr%l5AB%`8maM1XX;E#IM1)dsC9?NC3{tk z#GRyPS+6Y5{vq9)N=fT>Qym|f`73L~EEhhhC0qA@x2$m+bLk`DE#|wnHKlPlPT5+d zX*J@e6c1OIIa1|_3IK?^OhsYqtbIPtsN} z+Dn+H(Wmjs-X)#T_g_h_AEB-BDF&L=@@DQ!rM$Dw+ndWyB(eXdBlW9ak09|N#XOgm zRy~=cLP_f+%F8^?#3)IqAMr#OI%o9=Yy*-gS%KN$kyE{fr|#Bxlm1q=NVRHjDZi{d zMlE?viBZDYe6;7XJQ}n5cmCik-H7R|5pfIhe9H3eRT6*exJU-!k?dV^>c^%3>TZp} z;}oleh32Z7qo@2y`ZN<9XUt~RbF3DEYOmgkM`4b7CZcF-0~e->>mVBaSELRl+WD zRbxnzq|OlW)AwnllHR$#@X-~GMYU6Yq_g_r6xW2I|EfmfyQEIKGUpN=s;_a#ay4q{ z$uU_i>WX=#ahW%sJDOSQQ#BmroRRBDvZ@vJuXe;nNuxPJvRAXq+;xQ0D7>e;H5&U* zw+>qQb0m#JIiXrkzC-<*b%~)Kv(D*^^(HBF zq7ee27TNU!!l&W+uUvl;a+9PIJr8U4gh{#R%^mo`gm zQ|*Tr6aW?+>E!pxbf3*y?1@q!9GLJN$p*PjO9o^ zLK0beKmCwi(yEnK_RLxJuhz{rXGikGbyn({Y9+>+MXF;4JEK$$qplI_M_A}iqa+J+ zR1-f{JJr{o&Pk%gQQ@cY*dI9RNaMOsa_h%9Nt2Fj(uZWy+iEJUAIWGO?SHK&p)5I# zne~vY%cWzHt_Ta2I&W4PF|}cqh<6@?`KNo*8Dl3TWPA1wzF%$Ws=Zvo&lsh6<4nd< z*xNe}C8>n5%*Kv!wQ|+lGmAbbsp<3`5&1q>?Z$fB3k)AvW3&~}aR3|LNn7gAzQz*R3T#mpf zAjVX8i;sx~9*J5pQ;n>(iXuTd(4$F)$m9 zYMpf{#w0!q7je(}x8<8Rnj87OBE2`ICtR{&GugUJxF@!%?WD;hgG>GOkNOj*(>Ro~ zB-Tg{Nov_VPP168>JHDGJs*@snYRhqx<_$KvI$G1nvz^2(6bP|3#{BGY0uW6KE#cL zoQ@Kcj8Gjt*HJ&xte>swtz*44spn*VrfQ9Ov}#M-bp%YSua4tpq*_aMX}$`L#3f0m zv({AIvbBQbR$Ny+NI0srUzL<@KY5450G$_q^ahdF>Xi*>h1jD_yi)IK!T4w-_JEqB zTTAAkM_ad4-KVizpO(WOM3_q3b!<~SRhA}RNPc0H7*W@cxtH+N7<8}4Vx081j)Tux zyGbABnk7w4(HM=m_~uxsnSd-qNU9g}&J0#t`mqLelyu=zwR~NF6Qa7Ny25g0DW(4; zNxIK%O5e&g0`B> z`l;8G-ehZ*)z)k|j96VKZY#B*(j$>P$zs)7@@DmeG2yW9GW{J}KT?tBwu- z?NjPjtn;>~q)CrN{>9!&=RF#;%E;O`*dM3+>)KKs-~HbbYUE~_pV+3SQbxz;G=KB+ zPH7^ocPCZ?EkBAMb?Z`Wm$f?&x4tcF@oAjPqH==2@F6&$t zGDb>&je{)L=iFX8GM`cpwsgs^`#chlMc7&*;Ucyef0eGUzlrf$+43_-Td3obT9gd> zYfmL?Exq}WqOCY8L=rNN{n)PxV~QTdbuit5`eP0@vWVaMXqRx0B zWvzNNZb$p7ndG+giGgZK*L>aebR@ammTGuB^|6?jW~9ff8p(=OU;EBCq~HIR)a}{M zY^TqwmwW63&v!_n4`+;yTlflF!6VjSZLq+aa%@6XX|`2R=O_RNh@gT zNivEhnjxpGQmtxB*@JYQP`AX%YF5^mYp1*Fr6kdhS}^KvTO9EW{r|=+jY`rQJ)@}O z#6R1IbNo6k)@|Zy;(W3*x2HR$1wWVaJA-<1qSdnWe5$S`$!q4;^LO#U@|h7S7qGXM z4WztWV|K6Z)A~**2$Q5el|scVODy&o>CCGime6dg-CV;{$F>ta*Gww`!p?}-ar3dH z(w^g2ox$o`XX{==(x-FIMT~_Qqx+Hug^_vdad_0$)yjREJ8AsMv()dAp6ebU#n%*} zQ$3-hdUdQcQm<4d>(&^PwW_ZA)LlsfMo+cWn)#?9j^ZAGy!Et(gU0 zak0O%Pmp9rSO|zq@7;$NOt!j2{f)GlMvB}jALEz zZrA6HzW&;p)TXrO8J+u850X8#XA6@)jHOW4c+AT*qfVA0Je}tz9#~`MgW0FHEpiG zi#n1P{`);SWAD3kw_6eFwx1-WHIy=lWEZlU)Q5RxcBZ=|Yx0NnksEKzs+#tQ8jaRI zJiGbdEH_qe*FHiBILe8`#@wYws&SYb^+@PZ83+5MQPTEIm@%hPafHGA6un8iS6EPm;rTt*`^Zf?cMAj#302Nf9}coj&lHwIB8LB z8xLzunlSfPj)U?y!ch!$)bWwyzMjS_)=M*rCM(B1dvsfb^Er8igrTj&cIK64uM~-I zsa9R5@+MyQGRHM`$(|$?(jHH;ccWu_T{&7xyV9H)>S$z}R%_<8@sL(zduC|zImX|8 z3j=##*R#e~=B*=y?-4ianSjTUT1|X3qf}oKrrv$0?l9_>EZu7z+D;N*xRsy8OLNH{ zOPaE0s58Ng&~ai{^3ApyVIcn`3zW4|{3M~HtNNC_lE@gUcWK&uRR3m?cyE7Zjj1JF zalbm!`Shcnl8#l@J!7hApJKV|cUn5jsZn{JU|DrmC}~XAjy0^d{k%hMTLR;!`iTkl z${tOUL1R~|W}wd2rAmGHoZ8b~YQ-!RCltwrmvyR93zZ~?b!!=fg6HM7H~9?RrM9*G zH(zxvWej>7$(cjqk2z=tr+PxkEeQi7U`;9yO>baW%hHpuXJS3U@cm=swLU1N7dG`@YDKAeV!}HZRsj?m+G1m*0shg zY$T;y)F{-FW*+)hC_TH@XZ$s4)%5);ji>HU5>o}K+?IN(<0%$;B(^;>UH7j1Q%67f zO-X5)bGrX$0JMn&rs%%hUVKnU$lxBvZSR)q8a$-JaX_2yJ7ITk-%NOVXTW zTDcXm!zc-tl#}S3YT0I;b&E^Vu{C3~G;({H|LY}_mfVu$sIOt!Vsyo0O1{B1sXINg zq(9ZF|J1Qf82g$vYYVWYTCW~QJu6DBTY8ULj7nZhymi#@=jQdjU5Xy!tyerik8)npSYRo~t<%`YUK zT3ESW-99a;+D=i`t(bEjllCQR!Zek#E;GZtwzU~4%j8iDUwLh3OX`fzw)?M*WRhl zFiEd5%Ex)_K{87gGg$Jgwi%nGQbbAFtk$@Mp?p>vOWk)kGWuDp$02KRek&bVw;H)5 zm362uAEgml?z9qb|DN8%QhnX+w#7Mn4UNJmCVN+DG<1)cEx#tcNKyjrv7tZPQ7ct(mVc)H@VxoP9pMj*An=_Tf z_PW)pzB#2{^&@QTi-nr>p5|XhsXk_BCE}m!)msv7lHIMZ9Q*CbZLBP+3o&>h$K)CYQyg* zrOzj7d`3tbuvc(ROD(CSjTAwQi`!E@^{O7UZw{pJq*k6D@IwJ*>}R_1TAC5>J`9=~-e z9(z4n{iSPlY>bodR9^`>pVz1?r;$y5#r0Lkc-e=UF?G3B+Zc*FX$%QdwILbJCG*w( zC9(SdHFht$t}9Ejo_zs&+wcFd-hB=ZVEyA;(ODXEwqY$SQ6#JK5*eA5q&PIOjf_KU z8T)&ica8dHYx!7~`EH)Zbm7ECx1D`$tw?%~Av9mxj=61ltuxn=>#d+;WVZF`GGmqV zPiZ%%Xn3VDoDSz9wJ~JBTvivS_q5CNLj{+XN1_*wFRR4LF&1A1=o}0V!(v?AaFE^2 zz$TyashKZpI+Fb5kl1$&Ud}bDW6i$p_c7Y_RP`+7;`bHfY-C4x*6(|oK?j|ki&<8d zclAji15M0!uYRn#h{m!&mKjht26cD(AYHDn(V-`};aNOU2{ccYL3ojhXhi*~^>|S1;6= z*pgmXGot%OzVYv!pIZ-Q64{pt^Kur?X~Gvp7U%i9Lp9eiU6S=X%aR{wL|&DPb>XvaA?q9K?xvj99bMFuAnTHJ_2$)|-4{D{ z!o)k2;@Iw2wq4%PTcv<%7=%mOe4Yg=(97j;8?)Q?V)1a78Oc$}^R;Z2qsxy3Q8*Xu5$ z;t6i-x}M+jei+gscik6Ifs0I1ty8vHp>D}ZF-^jCI->nK@Oj~=PsfvR`#Jr*jU8EV zxt-iu4NtWgFHUZ8k#n?{Z@tQtRle?=Bs=szn-9vpW1aclG0h4oGtP1qr0+qh=pnIe z6tN_z8MZOAeS8%4?2%QkZ!FGU)iH0A9TytcYY_`q$mRu4JHO-5Isfv=D$AO5kZt66 zcs5KE-Hl#N&!cAbE*3C|X>iK&LrkQXLH5$4h9yG>Q2v}JB;e0S(MKO9*Xj0MiK`rU zn#{|dF^65v2}8Ai{4_eW^6}z8%N?6n^X08HjeR3E_9r{ZLtxS2b+dZic|DF*2c}tD zWpsBqblA%p)~UXYpQOw9i+XaDMhPDRz`&x>rb#Y;Z} zwfMeD1h2_t;cyt&ZOfEoADbbzHH_YmssGqJ54Yc$dtuDgGN`I2S-E`67X06uXRliH z@~#ZNib^_cRt3hgN#{94mKSvKE0nBuYRBnsX4=cp^@D0owTH!>Pvbb0MSIz_ToT4$n&PocYKys{Z~U?NWE)+KCpiy7SZ1#) zXJ4|CCRY1wGyh*l;s_c6&)G$_yxsou=WA(Emmm>e|)noUdh|huqrYTNyBvT@?`%1ISxlQ z8b6MozD422hUThsk=#ner>%2C)K=EIkE0VxLpp~Gwj5TnHjct)I1bU*-{n6Wzt3Pl zixK0 zBa5IGn=U(M@9R@O&#LL+)$DU8rs|Nr8_V`&-&N2$t+v)JwJCie!&7x;>$p|S3L789 zC4RFao6UeN+*)CEju%JLt%AegIGPka(%moXK5mw(0F4cc{;%5Zj!k36jO;o+%{b;~ zF{azf@)%PrV$k)br^$?Y4q?{6(u$+XuU4;nOLn%d9$qYysFuL(W9m=zj5rM{Nhrs) z;~)NalwXb8r)I~%Iw^kx;eI3QlajnL!IuBWSr%teb~kI9Ln)6sv+?tM{A+Y9c(?4H zt+qT$%cNr}X1bP0N1j0|DXj09*X+L1T8OW&Bz<~P@SiBJ#yWvoqZ!6ACFOgN?iSL zy)8dqpNH~~x_{oXJ;dju!&o3bvW*XT(~PREYm1_@THrZTfBD;A0QUr%70vv-90FD3 zuE6{EjQ{87*M0hTY4*EI7*`CAIjW%bPo}DXSNT+i_1NK)KCi_Sr+4o1AiJ6`=hb=H zfwhN`IilLE_R}L;Wp)`I4{Y0?)^X-m8R*_|D?rzKTYubtx{R>W#?^F-8y?@0`Q`k^ zIojC#bC;_q9H(9hMt3B3gnoA;7X{1@A>9m|@f?nDxd=jYH5RuPA6mlB6I*-^8x=SY z%Hr-=^)Dv$uf_dl*K8MC)mv1mW~x|Qc45W)KF+_#vQK`b-BozeyuHgw^*g^vp!=@z z&(~R~^1pS$m?VjiN_f{2%kUl9I?k)J_42V1qEy`ZlYMFp&Tg%f$*PCzqN2;M;kP^p zt?#Y_1L){|H8TFMzL1i2`m3zKU^9}5J=usmdEj1%zc+H71jA)va$*a=-l$DiXGEBt zV~ag#@U=64v;I6wYuZ$rs-RrbAG~K)0aVPgXU}XvqTE@3x5`##hwO6HwQ2jfwTy!4 z%es7N|C{^mS>cPwH-qE_#G6?x@SPW1`5SS^v;F3fzqJs9XGswWw_b~|nDf#T3^A_# zW@X=gKc(44!&;;337gd`_Ob?3v8f}_RJ-kq+VYhLADDkw@ogUr&gW#U%knIB)ert- zg)Ig_^(@#vX62>PZ7-U{ZmE5DcQI?T7eYSg1tu9?g>Jv&jj*1p ze>8LyT5?gpR+Ua?GobN%%k$-uzaH@~`RQi7%{JnJLaV4 zjVEk)Wo7K{m@68x#4XHTS+o0MT?DbB+KQ7HcB?9svfI2+a5v7jeNi|($nBn6E0NAA zIqOzuNyoYexxdCwcT9M5Rm@&*{T4~N@FF%2$+G;G-N%fphsUNYIX+~m^<-H#IYmvT zY_6Gn-skKIrTo+v==jSTtGhUQH#)90Yk34qd(A2;p)Zz6zMkcGcaV*5CWXOi6qV3j z4Ny^ZD%suqbS-<{ZE|1#tjKCeT2@U+kU_eUu2qWg_uo7kq2e5Crv;~2q~eq#@>I<$ zx77>J{zccwp>@d9;V&if?>+_D(+h&h0gZAu&n9c-Q-)(6J(B%{|`E2N5OfyvUp49*g4T`+e>!8P>kJedE_R zZI^o=Lw~F_v&ii3Vw^t4>B`>c?&@9qE{!|-Jx`xyAb2i|I%I`!s_d|Lb_Bi*h2zpoN;U0n85 z3pCPwujGW&@;j?^$X9JeKs>HeV4(M`N_tv#jjD8KAwI4YSGkZ*mG$*g&0SaA z3g$S>l6866CsjYGI~NK*Lu@EEI`6KMx!QQwpVn}xWA~gDweq;x|Nl$ zD$Q0pF%zv>mru!)-TYm~@OJz&a+&)#e2ds?8-3veue@pm8Q;fvEK;vMV-;?)+92BUe!`FUA{N-dGW* zZP|fU=Y{;YpDza;zp-1P!)rXuezD%Vr6Q%T6=j)Uo~mE?E+ba= zt=xGuJ8}4!N+%RT7T4q2E-@GJyUH*I@6Y29s1R(d^MAY09|k2gcgcJaif z*btBEW$K>#H?sR(xVz5+0kPOM`(-Y!Br`c(Gx~)o9EMQmjKi~Z#qJk9Jk65vbF&(^ zC?_w^#i~!3r(Q3ou6i$~pGhAnVxe9nu~+;ZH)!9;WG@4+3Yhg~;%s8s-e>cDbGTno zDcXx(RxHonSe{Hr)B4WRo4Z4!cFgMJEe`$bjQv|kUB47D6-6B%L&QLI`kb6RPg}37 z)lquMVY?nQYElFYLQ!yL*7~#yZ2eLf4>n<6kJ6|7? z)ZvjQAs4cB5q^0{ERu+0u)F+VSLfj$)|az8X8RfPIU6Q&OjZURQnE$9=VY>ru9Z;b}X*HA7D1*Ei1Z@w{!MXs=ea&Hv6o3txc-k za8JS_X-iV}CN24%R8NNbm1oDzH~;g1J>yQ>$#+KX@JF^cD<8sTE8i+qcJvCv&KEfn z%n<#o%%%@ku)ob@hO(EzIVrB z5<6$XqWj&Y$iP=#z4KzSzg8)yvNDNSE@Q(4E3d;idsrm~X&}R=WW{_}C#+49I)s0! znwmwg+Vc_g(d(V%#X!f`{#kX|w8*3b|6&^p$XZ;==HhU1={)O?QHQv-Ld0j6ICV?~ zSPc}PMkSMuRqD3z=swqeL3dm-=eW90MRQ%Pnl+9TtFU(sf@4K%xq&t0%;WG4$MAp0 zib0*5Z}N>vIz;%zt5>i4^deHcjJ6VWkJX9W=5P7W+vLn|GV%b^*w6@Ts4Nc0 zGU0gfV$ta4nUgJEhvTC99+%CX8PfT@ET4>jM13}A@$}(td*QZRV~G_&mRo6LvTvPY zOFn1eD{Y91b#ku;G_&h%&%>y1RjfL-ws*d##C@NZ1}LyGZABc`vLSx+dt-G%-~Au| z7q>9R%w~$ztpl(dQ)I@z;j7c$Q~1@iBKv08(CZAzke!V~25V)RoE~@6t`{laT)Q;; zBHAa&!~XnU#*_6Ona(w{|BbUfxt|k1FHC{6?q}Z=gnMUa!5fVtwQsd5&x~IiU z#^&Ya-B~}3CKYS9_Roj%ENj#9oni6n?$h8>n9&--!=^MKYx zKMlr;;pDt^qt#Sh-uDgl9;?(4TJ2UL#?)k{iKXIx3_o76eYzdLDDKH3D@13HZ|hq( z2HNsCeZ^ciP!{2I7Kz@A+5BfSwpxqQcOBi^QC#=0%9S}6zpS7e9$60W@JP06^yNxA zi{3X{I{WcBJI+Epl#AzO@f7v3p#A0NdGexj9^yU8R=D)ZGAFdaZ zu-ZMKBu`Q!<=$4F?Te&3UtVPm7Nj%DLrxZAog5PBv+nO!?&!(ulNwFeTeUD~%&r2t z-=LGhK|Cm)$2EB79SNBA`f}q*FZ$N~m=%L>#26$V-%`XI=FLzW;r@1wuvgJUDmkiK zF=XdPxq9k*@&2{=yR&=MV!6)8^e#SE+q*y0+<$-0`WJJJ9`HF&+{>C_5?*k%?zt|Dt2(y3Y8o2<9V4^x{N&#% zX?`x-^OirbwW2L6@+_Y5u(6xDIga5ARxfJpLHMfNxX>(?Z!1Q))!iI-hPy-D6=R+l z8CEepWV-uf^_YFh>?}(*quIlw`961+H`f!XAeat6eBjIfSIv-(t-kAA*SA<>WZNX; zqdc;fe2o6Q#tbWwEM1rp32C(Pk>Ra2*oOC{om&uTQywn zL3o;RtVoNA?`z+y{H>y49p?F&j^kE3(<09{f@flAPGgQiFgUj5^Y{9^oKN!B26 zrotpUM06c_51*`REoZSfs3J*wtCI{?H?r+T!2HQ>Pmgu7cP_oz|J#=Nc2$qP(10PW z?}#L^BYWhJxWpn)*y_VwNw8j=-s_ZkbMg-D>ARemWjrxwab8qZ~!YWH{$t!ycMS`KP{?2 zvvwArvIvsxXYG5}^v^pV#+uXIZxlqN<9pE{7@3G2U9*Zjd`8I8NF7HmavFzku-Jq-TqQ1^D z9J42>vn-4FpjNDBflniUN8Vhu&Q*o`953?2EX#*P$JAykNIrFTv6?O#r=_mt`wCt* ze2>y?Ctww;*`ZQHl{>`q=aAbhgzGxTSCK3HkCkCBUs*k#48 z2xQ{b6S`-2Y|X=s7oAqzX{Bctj46vM{~80KY7&O`mja$zPFGq&_KuOrZ@PvD>{!(q z^>aLwDdU6symMLIyu+1cY@6-L4{2V)IQyEJB!3C<{!NrD+Iw=6%fiKU5lGTS86S)f zg>VwVi?uH4e$RFlUk@IdY09hqFW2g&y6fHDxO&!lW#9VOr}VFls9WD7<93lw%6McO zGrMwc?*H~#zg*R}|FQ)ax9V&?V%3g9L5_v`8_UzW*sD+S(@MU0HddU%l6`n|u?Oea0l&V}zgT#8kg<*bWPSU~KDo^%%zSfZ zT$oLHbTf88#W#g`DbBmT!3#`u4bmA`=kico<5cT02BhJlb2?@5^vl?;vBY9?iiUL# zqWMl@>?#A*pX4?N2ZqyPzvvdX`ZDW>9wp5xwHR1a@7_|`pH7-&;5foc7&l5B**m+( zUAC~S&#+JO%~xA=05Yf}G2=#IU3Or8Xr$5Ft`8bB)4dq+-M1$D{*q*v4ZBq)*VJZT zPcrQtS!WOmY?1AULz0WpA#yg$aM}d9?^YW9A#n4=q zv3DyHe*Xyjyd`%lRh44>ZR<);4D_!}?7M;YiYuH&hehNq+S^WxG0QB-@#!r8&AoN& zDm89cftxcVu*&{flHXPX<Na1n13ow?*dniZ`T-f9veJt1)eyeLDl$A;MO(?7+^p z;gVdj%VYZ?@*c&`br|Grv}ls~w;Gf^V|Ce*YE*pd4u2{Fa5JHA8N>>UH%SlATZADy%MQI3z2JmN7C(9coN=UWUxp&2Dtj&TEwo zhJ|8{$y+7oL0*K_o<7?(d!yOC8RJe`lBg!i7pU_x z3)rDv=n8i3<+i7STYFW2(7Om@?)jHR=l|>RxXiM>&-$%S&2BZoy?4dZ>Akpa?$!wX zUKzGkYY1d<8pCn1v7NP~f3qtz;MweCssyeA(kd!4CI-p%?4mEd+p}F)5|hGnzVc!5 z7Mt{M-1tlGNAb^#^{X}Rir-qcG31C03|NH^TVH=~%m2mMI$YL-gKW!Il`Q@1&~FYM zMW9d6ll@s38oeNEOz)wxj{Q8Dz3hRGIea9=N*R;H?Txn4*qW4haFLl6;t_w(J~~BS z-4Na0XAiHhu2_LWG~^nYJXW#TI}4Md+TQmXw~}Ca%ImU{h4`N1na8bohO<_$sMfw8r6$ zY9I4NEv^p5?7%gQ=2Ln@L-ck<#HLv&>Z_btBldSZjM@uXwGz{fSOk|l@_#IupT#^0 zhg^Fq##Sgf#qzA6b?@_jS%xRe(!7SpJjkvrd=a>HH|Zf<7jaM6G}`?0MrLLCYPjzW z?a$8_p<=PP;d)%Vm)tZeZ~8ww-hXHFx*O-4J*klCNRhnrFV;p6GuwKI*7mKndvWTV8RHlm3aPCe|__p8wNi1Gg!J%@NL*X!z$DfIxm-#-acu@9?=5i69vN(P4%>QLs zlH`~eoR`^gXRo$>U*$E%Oa69N58OW4^GMDN7aYisUbLNGYFClyx@FaI+pSD;WaxMO zW6cZGMV|asDJ!Cyn-thII{!r^o4#2C6;?VcZX&#S(6Umk2e@;5BNqpcwUgO)pZR8= z550#|)kMeaDzx~WZ6_f~j!#zBj1%>tu2-s!%ZnF@MsEeOZFVf0JeCxt&8J~ji#!{$ z1=G^^BK_t!hPpb~N_RDOb({V?*&6e92rSIjml^pwCM7?MRh=voeO?yTR&tqtJX+;Q zGMjf~S6h9XwR@a>CwW#iL(W-=Tm`7MYKd!t5WPCW{${4hmC_x<%A&ka;f)RANE(fJ zqsBowAKDK?cXi@bN5dDl;bfG1KE>elb*3?5#Lmy|XN(sHbbQfRUs6TsJG!c@SS2^h ziu-)sx$%l+vX9KPufxhNy8qmg-SO~R6xjZa5JY+K`f6^R!A#z&ad4lG?`^T8N9;N) zC(N~<1WedE->CG5TsUA0i+GtYi$J4rT2)J9#~R-_HW~e0KW@Bg2+{tE_4}{!=^V1+ zDFbM-8WtfM)7pz&%NSdclEpxW1!pPiy;|VqJvZ zL><$|csj{bN^fr|HoZ5;cQE2g`#ne3ZyJ@6p)@3qp{(0}BZk*qWj6Eb?y}7H@cymc z?($@bS221sUEhK)ArUkASWQfJu@u>`Vr4e%Sh6=O3(K5wt1)?TeA79pK%`Ahd&e>P z4nuzDe-tyjZbQgvB9eYAbRPr$y$?h4Sey`0h^EIwlW8aMJ?)&`) zX-LIJeMeip5=3JMF2)Qjg$Eqe4&PIBBg89F^LE-dGuymCe9QG4u--|MAh> z)0|?Bhw zac@Qv&Fr&EV`OLgA0J#PVhR6G#*gA3DVsxbUO+vjyvJVre%B;b9&fD%YU)_FT!u$- z(;6x&<+ep}owT(ltzoA+Ws~E)s_xv~P}jTNr7a89kokjQtI>4@J+;)65%H-}Fg>1x z5G%_q^+T`iXnw|qJ)!3BXs^N_;)~F$MdiUCYlPTb^yQ@ec@Y+&H~iSJ^)cP|7Y}m9 z=sd}4Gh^cJZH5bUeb?R7+P;C_y^*{22<^tlwX8imCPST+=dihNNLs68!75(Nepwab zY`nZW_P#YP51=-b-YsU0Wg<^|(qs2oGF&c0zcGcawIEJiok_m@!xI+mC^kWVIf^(UM=0MqBIi2KR_kFb+gyH&W*Hz8czZExwrY{=t5fshwjcHXptWerV}57J zt&sOTJ&trXJ#RlC+CzGG0&TNom2TCbZ8*XqxvmsLfMudt_3mHv``15P+#cWNqkO>H zt8hswCNROwI~JnjqB`N~*ZnR%`m7ZHt7n+ZPU}nSio2Ti`1)Q|>gDC{*oe5QI?Re% zao2b$6^N_Qf$z{5yoA*71$``S@esH12G^d`H=t zcr_%FqOXBO`=R=~@`zzG#YCL*0uHYgV@uka@vgwdZFP9OD2G&XXkiHJ;Uu#s>p1Wc z{!KI&Bqqf~yRW5tv zUAofFtE^IO^WWHTEq`<=I+Ke6x%Qj6YMyU-(e<0>fkMI>p?hAnc(GkI(;?J3dnR3N zg%rIYmw8$2vUJZG@a^W#qKn_RYi)+v|895@mz? z1IuEZRX<;zgn8#?Me<3|$z+ZCjwveB7E zRt?A7BwQTwBoAOK*WdlI!IR5m6d4G}fa-m=Lpob$XQMjWcp5~a^`)wEYoa<>?a_tg zJ^N)Uo9@_ZnClc*L$3H*Ny}TS*(=AKT{&in&OFSD5zDi8)uAK3LNQ6R;(H6v<}Jdi z##`0ZL^{O8D$9OMfz?>s*z|}V+2VP8%eLG5fc^2r$hRlRemr_BMn1cPRrJ(>EI2L{ zF?(`>OjV4$`1#F{w98>JkC#}o&d8Mn%<&^1Ai%%;5b4uGCNyAKG-XS1bRFvVp{ou! zm=}Q4%>U=Dk>Tark^lYYZ|7RqL%isp=3;9N6%Em$>y01m zhfAYEOuXQ(X00p0x?#CGk**>AJNL5rxEXt`!q&Su**Xv!*y;YpfBfK-?fzT$@EQE$ zE6gtcu^@Yv@7cYKRas^S>v_J>FljGOme=hy`mKFMU^P= zPFzy54vN^6rF_KF)jcC;x3T2&k9Hp6RaRl^cq#H76+Lm?OxZkZppKCn5qjY}zwpxf zZmm?gXjo1xQ;PfLizt#6C(`R|k*|NLkNNj!+x<;hyD@C!tH`hu{(Kg%j+0yFSQ)Z0 zo3bEXzTvAfoX^dM*5yfB%`}dN-oLKp4Wqe^T+n{s!H-CB7w*6jtH}pG7d&f6- z$3lQDKK<ohN^?BI*~aw|y|R(IYmEhfMa+h>pMpIRFmM%{({*9YSqR`2^eX5SCz$=In%bVTluR=jrIUNyuR2+Yzyk?ed- zP5S5K5B}!XJF+2tz2N>E>IfL<1(`=Pq)`*|VyGBlf=ix?>$zE3=n}=e=VuqZ*NJc3zf|65Hi?y7QvZL!=7P z%-#Kv*ZK@+@^)3k_gm^f^`LrleU#n^4?^kqd9^PK@L(A$bF2xoOAN$U{YhG{9c$Yw ztU~zW-_h;!5;l1nFWQP_$IUZN4xL1wCQk(7O?}0lK1^n3`1Fn)J4O7i2x)C(@_D2} zT`v5b_`%6&EJ_C}+IppBv-4$Eejf|hHz&lSFSTFqByt$57&x0(^x8Ig8cK^NfY01Y%k)UE(d%H{Ei5a~}e!8RSsgUZL zDiz<=JXPSo-($PAQC#x67e9FU?j5Fi-I>>aN7QCnmrd)))q%$Fwk^)W&pZ4@kN%FZ z3Vz2DSgAWWl{}oOT4L<`G+nvdEFB9Lhjz2w=}x+9$NffXTJ!d7{S5he<$Fkn`}#1l z=PPa)JsHK%cjt|T{#%pMpG}=nzixZ+$tHXgpX%G+b08h+^yO1o5JHE!IEKy3-eI}* z0Q>U?zRRHGh{n)3&lbDQnbjolbJe(5CkLG4NKTk*oW|FeC6Uz?}PR(0Xkfus4+CzjsmWO=>J+WbbR-HLH@`7_4+ zBj9Hfe`8M;-CYF8rq!o+OrEprwIpHN{}KFon}zmqMSSayb$R;jU9-tU{A^Yh4^?bQ zOGo8emcQN(*K#Jz*B_8HxrY)tNr1t-VyhA9zYJ_9tQYgF>UF-d&Zy39zfaSmC&}xM zxE5fq$eoA3dxYewn8_O^KPLP{z5I(`@}jLMjup^a#he!#@19@lkNTYad>B4-t3@%b zQGAL$m?6_{6;d6tg0HTOn%j}Zk)Ev0s~6Ar*hUuxc3HPr(MU%-E6UcP{OyI!^7r?G+0y^9~M($j4pu=vFZ-&n2BD_)Q znb%MjcTXy`F40X=k&v0gg#Yh5ba(@|VKgf-tfM$69*xaDmW!sRc;0_ot>ZG*Rb+V% z;i`odE#8JKo`oD#nhD>-*{4>6eJ61DKt&?yo+H_aDqoUftEi?M%bFu{y2PQ!S16u# z*e46qX6dmZsb09f=NFSMqvjiqV+>9=Q)kf~6&>|*xLLWF|>m2DDXa1zA zyD>Rdd`EE%9EV(G`sEm?9UJ%&Hr7z9R}tme<$s#3pe-h ztG3n~HZ2Y^DttmdUis_W{qkiq^J^KTzL45c`E_W9Qa-CS)-1CjCtuSw3~< z8-*lgmHGUHm7JijnZM=X0R5ZaHhaW})`M<*$pvSau)&u;~=Ak>qZ-x#Cf zWp5bCKvw`5qXv;V3zOl_Sbq)a+d|c>aeP?pF*vzKyz*e>+UkBUCCtjeVM2GdiBp}3 zxKz2>AAj;KFVr_3Qutxhm=i|)jET6Brm-Z{W7Yd=|EgZTG-C{!Z<~p!EP-S;WX17$ z*}4vaF_pgjCOSW7uJQS*A~H75x3wP>~{)?y!1Cxu+Q}jrzQO z#*1yAy-1j(9mN6sgnAlpUA+2pXHC_!w$1QaG-@a6Y##%YmSUB1}! zW_GbT3##O^4$&{9O~ug}l;F z4aabA6dz$Hn^Z#A%+@y7K`QfN1gp>VAC9HL6+z!Usvg!yeR_7*r&SG$+ED#`_#Ba~ zBJyU&)y=D97o$6t-|9phO@aty-Reia72WYIEAMY*zdP4SgDZ@RV-o29u6y&rRwgx$ zXIatS%Q))-gwidhabBg{jPUUpZZa^;)3wzl{_a>cdYr?8&<%yv{#z$QhqcqUEhaS+ zmgPYfkQH;`aK0V)z8P)(I}7Q=E10r3wwrm8x+=PBZmZHNM!pX7A&g5yO9Vs^V&75u zO#iRQBLsTN-{b6+x}*{tCH)R*uN~1V`@;67yI<{ zH*PKRZIh%IS3TPoyLez^Qq~Jv(~JIes^sCp>u>&kqZ|w7F^PxF&WtJSoP9iA#=e!h zdC5$BXuNpl%OcNSJdGEt+r{}-v*stMKFbvciNn>y-R@<#~9aD{{FRC7A4tEs>;`_ye5X3n+~fl zp4FlFy}j&p=So*`60)&9t4|oNI;3m3Y)fZ)7x_kA)_gvGteKs8w--j1BY*4r;jnps z+a`C|PUqi_h}cHXO7=oj1+aQ`Jp6`re$KbHqTdKCa3sBsrKh-5#XLc@rxmvnH7@V) z?yd~1(aX$6+!*IV?)Nd{=bbrNqgt}}q|JX-M+RHH^CV0$0lLjzjcaCpV#oQtXg7PG zhm-wxPFzSz>~d{Fr`pEPMqEaY@A4LUu+F056tZ%6h`(1=R>-`9Qn>6oy{K7Xx*y8gLKMXoL&W?CrMSCzQOb_sL3X>*^^DZFk^g$Q`*i( z6z;9V_ zb$FOg^V;S^d!pYSHj2?kG-sK?*Y|3r?yM+TXX;NyV!X%ZB(kw_F{dl2;yc-k*SHJ` zF=SWFF5Xr(S4Qy2gZYvEJhqirX-UR%Do^=HW>u;Vqw3JV;96BLdUO>-c1%u;Sx+~V zzV*L6ODl#!JSoffeRe)8v&#xzmn54z&a0t}v&~*K=W(*r6Sip?jv{Nkb96V-I5jZt z6@%rT+UuB19%Iu(dQuPX9djOk$qRQ(!MiLBNl!rN$r_1|=Fri|GHBoEX9GP+g2p)7 z){D>Ikq%L|-tpbBSf7&QlQMsdAA&qs=D;xArc>v6l9&I>gKS`N=!<{zRf_yGBNWY9 zeUUr6=eIkpDrE>C(`75H(y%xigE^}X>m;rw@`?9j692q+UhTU67E6m<(y@27=}*=* zyQ;ch@vO>@Z%Hq%WUx3}7F$@kV)U)8we0+CPL_(uZLRpT4DfB-%x%*~csO)7f1Y=g%~DWmP3Bj?Ick?^77Q z0e?Ak`4;wdO=@eEAs>>Hr{~WQP&-t$-zcpHIlinJV^%vL-23HC-b_Q7vZxtZad8}; zZIkexYyK>LqtkI-O$&>v@T(|gQZ;z1lsh0$aqs7<(0a^f$ed>GIo>f+Ep0?N@PfUI zT4#z>BgfgcogX$TQtyq@k?fwpYT#njsF2c^uxU7|EbDBFPZnj_i`uHiVGD1awpu;g zSjx+F@GS3L{HEkG~b$Wg-xQ}jKj@*>xK%^+4vKRTg9sh$>13~FxqO-*>%6N z&bq6XjCJ8W^pd~M=lzwWW~bfzqV<9Gb9Ag;*Q3_BKeuT0Lgj-*H8y4eyciwkQ;RH8pz~vU3WEFPD z+j4SP_@>;qY+0xRLj!h~!|I@Vw+`_8Z+AWd{_!f*u}{YI`PDnlWnuQJ&M+7foq2oO zd9W>f!=5Hm=0kS#974J_nI;~-L#oD`pK=v_M+)sH)SY1!k7E64w25K5e}8VKvuFD(EZgv=3ce>*Rj1^L2pyuHu3~J=X+GKP`4g{XSv|Jm4v}4( z6sP2f;&~!oH1y75Yl7$K;@8;{ZnM4ddy(MWvZbw6b)&W&m&zQLmgjF(PX}q^j!Geu zp+r9q!bGJ|zg6EwC%rc=NqkDq8}rL{b~pdcI_R21`;cT^zLdWrY43DQ*H#b~742%~ z)}q#+)@T*SQERr^b~Q0iSBK}t+4FKKyYE|%>Z|syJ6cD5mwZ=9yiA)Ji%+;zuRJZw-}%{`UgBp}i^+EvA;er;$-&;$rK-c_rK}Z$ z<@mPhc2+sEyc;V!dNG4AOx~4L1h%rO99gfk5ydhA(^YLx@m8(EsX4tc>b!=TE`8sL z;6qnhMYQ;>_Xs6x%eU3|l27s@)G;oPAU!S*iTDwJ)UdjfaL7vRzMM3M4Kaa4>}jp+ z7%nt78P=Inj~w(bK{Eoz*nRe43lh}_MuZB(tL4*{rR_1PPmwoKQ<;~btYu3^E`_3_L3MQ_=Yj>R}zFSf-C7GiBR%>uqO zGi+lwv{|R}jPr|CmWc!%*-LjwVMku=%H%lkXUyr(ZeD-u7(!~I>cK{tU>@DapY&yg zyEJ@N3)mZ)WxQy>c^-`6TP5!5$(h-SEl|Tmev3u%4{vp&HI{XvQeEh*EXudolCRgz z{oXGgCu7-e&YkO%{=l6B&u`B6G-BASU;JZ|b&zCvBCA!n?6FoQ?J}bHi5Uq=YGnSm zon%`c+{lxZC3v!`S5zAhMOSdEIveTQ6K*)J@_$r+E7?ejnM;N(cQ<6}O$|95=>E{d4Ewer;eyF;e$$`st#|0kTODYG z^Rs6BJ&cPteuxepo`pE&{-@LdDRV$-~DDbzlgt{yy%V7$w;RA9q#A1 zmz+0m@_liTGmXNXRnp~^4ybc~o3+t9C#%U^+9b1Nyl^tdrqgVlPGD2jrq7#Z3bu*KMRlJ`so6kaX^Jstl@}D2+ z{T0lvMrm6-@}$mtfAgGA$%k07vse}{2aB0e&V64M%XMS&Yj(W|eh&V;@@e+aBrf5= zf}PLz@vo|8rOo!L++@d|;gPj)Hl{gx-97z!o$BfJ-)kR~+*tXZb>1gk2UbatfHsRi7;Z~H6=kf5(QW?(Xn>nwNniqMSZOu%B zm43b4at5X+GkG_cJy(H}ll18x=2*RR$ykkhD~s5%Saz_vc`{a~wAy+sEz4n^ybxK2 z+%q*H)hiosO=^GRt*MJ}UNm-D&}?17qIKVF!?Mvl#sGIg_1rHK)(rgi-r1q5KhZm< z6ISAr9#)K-SU$Gz8h6n<*62L?+eodP3^%^kaQ8=D%1i3dJMz$_IGK8WwbJ*2F7O zfm|}vTwd=EW>Q2Wt6qeMrLBmv0lt487wuQZx8&x%v+^*u=ZDPr_8JRB4jQ}j>Pk#L zB=P$tZlX|Brsq~#bt-&1yLB@k^Ffxy0{d)!quKH0%iU9mr!R`~<-QB+TM9iCxfqiz zvcr=Bo}YsX8!$H?MIHm*e9Jaor~ftjE*Vq1a)S>706A-oUlddEQLSn{{ctW1+I>G+Io( zC&N96GMJT(5I<q_2lWMf3*mgVC@^D&|$XPL@fboRP&#&`VuIj=ja zdam^qknin@ z$@Ok9gRn7h+E_Ki-ZGzOB9O#L4Y<6!&h ze@_run`Os1^F}R6W~gLv;)ydC8~3hU^ZM34`<=f!nIBdXyxsT0Y0c^|Uk-&53_Fft zw)4;RHJvJRGm2B&@_rRZmzIuji)(K@7SB75>qRJBjJ|g{A*06VYHRw6W)}H2mMx;E zmu+qx(X1@v<65>&0~GXF7-N;km`2JLpYrt13`6`~<))=Lyj)LqIHcDq*FD4TkQL2h zQkLcCd%co@LOm9xv5 z+TS&`UbAD!PDimR8h1QP(!_H0Gp}%u5BPGCFdOdX#n7H`>iI%XOR<-y=3i}2Qs-NT z@Xmr~)+9;(%z|(m(%-puyf7=BS>3wZTJ=3T*-&CfI5{#~57W11HLurY zN*-66Pr{-bj!?<^tfphzMRJ+*E#>ThnRu_xh}R)a=5nREIKQai+dP>C-?I+4FfLE( zjMtT@G@j?aKE-+%BE5#nTS+#9bpXUA-fYuf*%^Qi$;Xh>MgZew{_;VN<&u>*Yo0I89 zdb4q2)|)rvlG>U4n-`?eB%6Gr55xP+OJK84BFvD072Ay$h9 z4KXDoSBYpI9wdqi{WujT;(W*OEom_0J9M$@>|4~x&31AwR_gf0s88#5>SK!H$C1yA z&&kgAyMqFe;gW_MyQ3I3Hg07|7J2&)E4dfxd^Jbayh;Q?9eUQP9`yEJtkzAZAv=nq z%Fs3~MQdy6?}&&tJclBlf6Ef_WkcSl@ATgsxMT}7bUyKf4V`h8U!mWaBz9(ulvnaz z-A|$#W^5L+gS>3)&a1zE^h;ii@jrPGg-8qyuVkuFcfFoHA7MXn3Bls!nqpV2q{i!A zC#Z16DIZp+Whg#3dXdICd6A}BIgaj_zQZ_viuu;|H{S9#%ky(SK&5{P*)MWd8<%A| zFxKv_wLbVahnkhI{?@+hnIac+(z>dZZQGNvY|5KryJI}Ll{b8|YB4V2;mU_}^qHO4 zr;j`Q!LMfd73ZS)Z4Yij`sIuqkt=b6Pm>zQvOBCitL--;cc-r{*5QaO6@fS2vP|A| zJUuW88+#qq|Gf9pMQQf5&3Z4<&URO{RphE=Axn zaJ8iw{Vz*cFK!UX+Kn9-8lM#%|9x*H9EKY1ll=PA%$N~J<3Oym=B?{VO8P}Mt5n78 z$4}pH(~z%mrMvMxAM>w|+^x7I@O`*XdNym-_&sqI{{8v2^3H`K{KN;g%7$r%LjDO!-)jJ$ne$0p=B#4T6SB0h}yvJ9yW*Umx zUc>*^jqmw+zA@u`dhujZvImZinDNad5yDQWHmi}Rp}k_j_80Z!zGIWa(xTUy%Lg%a zwtH6Yuc{(1W%T`}RQ;t3c!w%QTF4 zc_I?Ok7d#IT8luoVV3a_?Y$A@e^oOt-}CrBoFQU{k&P9VA){C5id8R@SMytEkd{Mm zHt{8&mNQw>9-Q+YM?1Q`&RwO*l3qh*HOZ?bv&uCKHkgb}>Ez=pa&<$FJ${NHsiogLE;W_>oCOqpR8udqo3v#0$m*_d!o*Y9I+zB6MLdBwmS z9DuSYHk0S_0{g`mLf(@wPK%H_yt!v1>BDhc8H@GyWx^pmHYK;}8ovI{R{o}$hmC9| z=66>FM_|=iSmQIBKa>BNpJl}a)2@b^w>qN}c%ugGX1%x%MN(fKGGw+E*>r_3@2ugn zIg3xKisY{PIuu)-TDFt>UFXt~eU6GGoUX!MUz?{L&mMNg%WS;0v$*wAfx|m_>F&L; zSv`ao9qf7QYU6O=5KPQKbf zciLgu_VT5SaxMMZ*XL|YKRkwu`Xuge7dG={;}Gbt~B_Y=!`34eYze=%4;Bu+bD zoeI}tU37M@s=8NSUX>5a@0x!+Rcky$SB`cS)95T#30FVcZe4UXy~hFA#0t8K{*8k~ z5m8xH$m`(7N8>ONmtj*3=z@<-{M#`cP<8VmDalw~wB4(*XW5Mv8&Rcy4CLK@B`&Nw zk2j)KMG1X8J!t+=hL7PIw3EK%K>|DCy69nP!CbS%0Tfwc3!@!yPv0mc-!|Y&lfv_A3fo0fq^5wO3l_o2CcBopQmYe(I(&N``i^VF+#?8C7y|R96W+}fz z=V!oY#CeisJe3D; zHA$eokz+N>=??)KTTAv$PTTf*l(l($$ec!)$|Sxwy0PhQR{KR@E4jYS`p}tKyo%0i ga+{kj+Tne;lTQy%Ve`tos+WwjDVcxTX$-6XUlE9rA^-pY literal 0 HcmV?d00001 diff --git a/res.qrc b/res.qrc index 4ef12f901..5f3cfe467 100644 --- a/res.qrc +++ b/res.qrc @@ -123,6 +123,7 @@ ui/fileTransferInstance/emptyRGreenFileButton.png ui/fileTransferInstance/emptyRRedFileButton.png audio/notification.pcm + audio/ToxicIncomingCall.pcm img/settings/general.png img/settings/identity.png img/settings/privacy.png diff --git a/widget/widget.cpp b/widget/widget.cpp index dfa25fffe..708c23fd4 100644 --- a/widget/widget.cpp +++ b/widget/widget.cpp @@ -145,6 +145,7 @@ Widget::Widget(QWidget *parent) connect(core, &Core::groupMessageReceived, this, &Widget::onGroupMessageReceived); connect(core, &Core::groupNamelistChanged, this, &Widget::onGroupNamelistChanged); connect(core, &Core::emptyGroupCreated, this, &Widget::onEmptyGroupCreated); + connect(core, &Core::avInvite, this, &Widget::playRingtone); connect(core, SIGNAL(messageSentResult(int,QString,int)), this, SLOT(onMessageSendResult(int,QString,int))); connect(core, SIGNAL(groupSentResult(int,QString,int)), this, SLOT(onGroupSendResult(int,QString,int))); @@ -535,6 +536,26 @@ void Widget::newMessageAlert() alSourcePlay(core->alMainSource); } +void Widget::playRingtone() +{ + QApplication::alert(this); + + static QFile sndFile1(":audio/ToxicIncomingCall.pcm"); // for whatever reason this plays slower/downshifted from what any other program plays the file as... but whatever + static QByteArray sndData1; + if (sndData1.isEmpty()) + { + sndFile1.open(QIODevice::ReadOnly); + sndData1 = sndFile1.readAll(); + sndFile1.close(); + } + + ALuint buffer; + alGenBuffers(1, &buffer); + alBufferData(buffer, AL_FORMAT_MONO16, sndData1.data(), sndData1.size(), 44100); + alSourcei(core->alMainSource, AL_BUFFER, buffer); + alSourcePlay(core->alMainSource); +} + void Widget::onFriendRequestReceived(const QString& userId, const QString& message) { FriendRequestDialog dialog(this, userId, message); diff --git a/widget/widget.h b/widget/widget.h index c9d4e6388..b7abc60fa 100644 --- a/widget/widget.h +++ b/widget/widget.h @@ -104,6 +104,7 @@ private slots: void setStatusBusy(); void onMessageSendResult(int friendId, const QString& message, int messageId); void onGroupSendResult(int groupId, const QString& message, int result); + void playRingtone(); private: void hideMainForms(); From 19199670827afb7e92c630650201557a1b7bcab0 Mon Sep 17 00:00:00 2001 From: Zetok Zalbavar Date: Wed, 8 Oct 2014 11:57:41 +0100 Subject: [PATCH 204/205] Add initial Pirate translation --- qtox.pro | 1 + translations/pirate.qm | Bin 0 -> 5594 bytes translations/pirate.ts | 545 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 546 insertions(+) create mode 100644 translations/pirate.qm create mode 100644 translations/pirate.ts diff --git a/qtox.pro b/qtox.pro index 879112e5f..edddb76ae 100644 --- a/qtox.pro +++ b/qtox.pro @@ -36,6 +36,7 @@ TRANSLATIONS = translations/de.ts \ translations/fr.ts \ translations/it.ts \ translations/ru.ts \ + translations/pirate.ts \ translations/pl.ts \ translations/fi.ts \ translations/mannol.ts \ diff --git a/translations/pirate.qm b/translations/pirate.qm new file mode 100644 index 0000000000000000000000000000000000000000..c245f536e083b1e475331d727597efdc80efd548 GIT binary patch literal 5594 zcmd5=U2Ggz6+VvFYp>T{Z)?Z6O&VPnf)ixYHc5++N`vE{#8DG0|0D{CpYhDy-Kl41 zHZ!xf_YH)A2zYAg4>S@&Z9#oXBq%~ch!=h%fmG5~0@Me@1B!%{2T-Xh@$;Q~cka$^ zc9A0TfUVuxJ3IF~=brPO@1DDl|HzrTe(TD!znR|u)6ae9CvTr5>bpjRTNR>ven!Xt zl_47b6n*sVV?_CezK(o_=IYN74FvSbzdlMdI!iD9^9`b+M?XIkVcsqJ?N{FN&k~KF$uzFSurrf+;qo_#3X{$2 z>zS+jE)tC#$o%8QKNIbFdf+2xUV=S);6&vEz^M;>J^wQ1eQ)50FT;N3-E1(jNHo}= z4Hhaf-+k^lo}0{PPP-U?Hvi}ij5F@YzU$8*KEED0 zbqIFvIX4nrfWNu-MsCgg82 zrzs#0|B^y-$)_25i01LRK@r7d;hTsAo|(b>62>8YnAY&LY(6dUy~LBT8kZ>=0xV_m znwYCQZt&1~*O7sUWE{JGIYJmIJ9mC52&;YUz!DsA$pM5Q`;N@k@U*0D%$BrcjNW@1 z=ESzLSqtU1D|b3gE;RkWO9s~}!Os7I!Qr{{Yt0y|z&>%8vRJr1f1RcTXe3qk>c~cn zOg1nMn;A`KCqL&nVkvZ`?}-MNYhfah+-y z`S|4F8qgMI_*6DzxPLJWgHY^LTu%xw2)4jLQLl-Gb8AeBF4iBX6~%G3T7?x~E$1Y# znc-X|Tni<3~ehuHvS|7(;cnsYcQtb_c2!pt4zxm78u zR%271=n(~n=8!ecn~(fekz1xTQ=3<1;awQ|Z{nK(Pw9N8$-aXpS(NK4_q!+prXq{= zCR5b7G`-==-I}yx=?K4G-ISpSN+OoKF_L8mVb2d|1oR+e Rx(To*Co`qc89UU9r}4KoUYZ6i*kVE(6u!b_ z|2oiznzWCNGlLtoUan*z2#`DTXm-xFWld@QxZb~4wfZlpcqo=mc2|6ZQP309`$kW! z3|fM~%*?LJr=V)QsGc*D8c8%x&oH14eRu+yf>jk%z zIy##e?HZT!YgLq9L#$Z#R!=7j^du%FUFM9LJg{DoRkba2_2U4hvDGp-!>Y-;X5-5H zH*#cPiW|_HnDyRM8-i+(yCObJ7Z7%49jhO=zGYl>TbgW<`sk(`;+CtUYb;u}mbr3k zrLNt!p$R%jj{vfYys{B?mY2Z0wUYOi(+3|B^+<+l+h<(H96iN#bmxfgJ7=1dHcUQD z7VoAZbv*5gm{+c+>b__im1Z+ymOhFdB@{Sl`mq}~c-WwcM>>yA_$vOU+{;+@J4Y7JFL#l%`$$xd~su0G`6b_UbZq$oCg)^hy| zuI~gps^~w6PJolljAec$jB3*pYH?};iT2A<^;~Vo{7&HGbQZ9@P3yx%slOC68 zV$3klgnN8Glon*#(kiV;%t7z8@^Q7Vv5n3Kq7Ev*xsK2I2$=-*somIgC7ujZovi|bvj4$&ojGBGnU zmq43t!Qov(A6xmI&mHNkwsKlr3EgeWZnWhy-@Iwq{e(6Plso(7MoUVo@hC9K^-nf& z^8|^8+bhjmRZf9ogXB z#;^fCa^sk7qPbTcFWo8*^aAJ1I0(e1tHd*ncND>B@76lcHhkD)ndYXI5ACgfZE8dB wm?-a{Cee`cd6u2$9HxzMZKh8e9E&bgH?H5;0!H;X8d$9)jeHqa_Vo4r2gVk%@c;k- literal 0 HcmV?d00001 diff --git a/translations/pirate.ts b/translations/pirate.ts new file mode 100644 index 000000000..85a149a95 --- /dev/null +++ b/translations/pirate.ts @@ -0,0 +1,545 @@ + + + + + AVForm + + + Audio/Video settings + Hollerin'/Crystals o' Far-Seein' settings + + + + Hide video preview + On a button + Hide crystals o' Far-Seein' preview + + + + Show video preview + On a button + See crystals o' Far-Seein' preview + + + + AVSettings + + + Form + + + + + Video settings + Crystals o' Far-Seein' settings + + + + Show video preview + See crystals o' Far-Seein' preview + + + + AddFriendForm + + + Add Friends + Recruit yer crew + + + + Tox ID + Tox ID of the person you're sending a friend request to + Tox ID + + + + Message + The message you send in friend requests + Parchment Bottle of recruiting + + + + Send friend request + Send recruitment letter + + + + Tox me maybe? + Default message in friend requests if the field is left blank. Write something appropriate! + Tox, arrr? + + + + Please fill in a valid Tox ID + Tox ID of the friend you're sending a friend request to + Throw in here Tox ID, but a rightful one! + + + + You can't add yourself as a friend! + When trying to add your own Tox ID as friend + Yer cannot add yerself in yer crew! + + + + This address does not exist + The DNS gives the Tox ID associated to toxme.se addresses + Recruitment address yer usin' ain't there + + + + Error while looking up DNS + The DNS gives the Tox ID associated to toxme.se addresses + DNS witchery errored upon looking + + + + Unexpected number of text records + Error with the DNS + All numbery that DNS brought upon was unexpectable + + + + Unexpected number of values in text record + Error with the DNS + All things + + + + The DNS lookup does not contain any Tox ID + Error with the DNS + + + + + + The DNS lookup does not contain a valid Tox ID + Error with the DNS + + + + + ChatForm + + + Send a file + Send treasure + + + + Core + + + Encrypted profile + + + + + Your tox profile seems to be encrypted, qTox can't open it +Do you want to erase this profile ? + + + + + FileTransferInstance + + + Save a file + Title of the file saving dialog + Receive treasure + + + + Location not writable + Title of permissions popup + Cannot bury treasure here + + + + You do not have permission to write that location. Choose another, or cancel the save dialog. + text of permissions popup + Captain did't give permission bury that treasure here! Find another location or abandon hope of keepin' it. + + + + FilesForm + + + Transfered Files + "Headline" of the window + Treasures given/received + + + + Downloads + Received + + + + Uploads + Sent + + + + FriendRequestDialog + + + Friend request + Title of the window to aceept/deny a friend request + Recruitment + + + + Someone wants to make friends with you + + + + + User ID: + + + + + Friend request message: + + + + + Accept + Accept a friend request + Arr + + + + Reject + Reject a friend request + No + + + + FriendWidget + + + Copy friend ID + Menu to copy the Tox ID of that friend + + + + + Invite in group + Menu to invite a friend in a groupchat + Recruit in group + + + + Remove friend + Menu to remove the friend from our friendlist + Throw out traitor + + + + GeneralForm + + + General Settings + O' ship settings + + + + GeneralSettings + + + Form + + + + + General Settings + O' ship settings + + + + Use translations + Text on a checkbox to enable translations + Linguistics use + + + + Save settings to the working directory instead of the usual conf dir + describes makeToxPortable checkbox + + + + + Make Tox portable + + + + + Theme + Lookin' + + + + Smiley Pack + Text on smiley pack label + Teeth showin' box + + + + Connection Settings + Sailin' setting + + + + Enable IPv6 (recommended) + Text on a checkbox to enable IPv6 + Use IPv6 (good for ya) + + + + This allows, e.g., toxing over Tor. It adds load to the Tox network however, so use only when necessary. + force tcp checkbox tooltip + + + + + Disable UDP (not recommended) + Text on checkbox to disable UDP + + + + + Use proxy (SOCKS5) + + + + + Address + Text on proxy addr label + + + + + Port + Text on proxy port label + + + + + GenericChatForm + + + + Save chat log + Write log of yer talkin' + + + + GroupChatForm + + + %1 users in chat + Number of users in chat + %1 mates in chat + + + + %1 users in chat + %1 mates in chat + + + + GroupWidget + + + + %1 users in chat + %1 mates in chat + + + + + 0 users in chat + + + + + Quit group + Menu to quit a groupchat + + + + + IdentityForm + + + Your identity + Yer self + + + + IdentitySettings + + + Form + + + + + Public Information + + + + + Name + + + + + Status + + + + + Tox ID + + + + + Your Tox ID (click to copy) + Yer Tox ID (hit to steal) + + + + MainWindow + + + qTox + qTox + + + + Your name + Yer name + + + + Your status + Yer status + + + + Add friends + Recruit crew + + + + Create a group chat + Make a chat with yer mates + + + + View completed file transfers + See treasures given and received + + + + Change your settings + Change yer setting' + + + + Close + + + + + Ctrl+Q + + + + + PrivacyForm + + + Privacy settings + Secrecy settin' + + + + SelfCamView + + + Tox video test + Title of the window to test the video/webcam + Tox crystals o' Far-Seein' test + + + + Widget + + + Online + Button to set your status to 'Online' + + + + + Away + Button to set your status to 'Away' + + + + + Busy + Button to set your status to 'Busy' + + + + + Choose a profile picture + Choose yer flag + + + + + + Error + + + + + Unable to open this file + Treasure cannot be opened + + + + Unable to read this image + Cannot see treasure + + + + This image is too big + Yer flag too big + + + + Toxcore failed to start, the application will terminate after you close this message. + + + + + toxcore failed to start with your proxy settings. qTox cannot run; please modify your settings and restart. + popup text + + + + + <Unknown> + Placeholder when we don't know someone's name in a group chat + + + + From 7ba9ac69dc8afb997ffa8742f79cab914b9d01c1 Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Wed, 8 Oct 2014 13:49:11 +0200 Subject: [PATCH 205/205] Embed pirate translation --- res.qrc | 1 + 1 file changed, 1 insertion(+) diff --git a/res.qrc b/res.qrc index 4ef12f901..4a8180ced 100644 --- a/res.qrc +++ b/res.qrc @@ -138,5 +138,6 @@ ui/window/statusPanel.css ui/settings/mainContent.css ui/settings/mainHead.css + translations/pirate.qm
\n"; + res += "\n"; res += "
"; res += content; res += "
\n"; diff --git a/filetransferinstance.h b/filetransferinstance.h index d1c9062d9..fb54fd8f6 100644 --- a/filetransferinstance.h +++ b/filetransferinstance.h @@ -72,6 +72,7 @@ private: bool remotePaused; QImage pic; QString filename, size, speed, eta; + QString filenameElided; QDateTime lastUpdate; long long lastBytesSent, totalBytes; int fileNum; From a18070d7c58a334b43615e65c38787a351461008 Mon Sep 17 00:00:00 2001 From: apprb Date: Sun, 28 Sep 2014 23:39:26 +0700 Subject: [PATCH 105/205] Wrap name and date fix --- widget/chatareawidget.cpp | 19 ++++++++++++++----- widget/chatareawidget.h | 4 ++++ widget/form/chatform.cpp | 4 ++-- widget/form/genericchatform.cpp | 11 ++++++++++- widget/form/genericchatform.h | 2 ++ 5 files changed, 32 insertions(+), 8 deletions(-) diff --git a/widget/chatareawidget.cpp b/widget/chatareawidget.cpp index 765d9e96c..c2e7a90b6 100644 --- a/widget/chatareawidget.cpp +++ b/widget/chatareawidget.cpp @@ -39,13 +39,11 @@ ChatAreaWidget::ChatAreaWidget(QWidget *parent) : chatTextTable = textCursor().insertTable(1,3); QTextTableFormat tableFormat; - tableFormat.setColumnWidthConstraints({QTextLength(QTextLength::VariableLength,0), - QTextLength(QTextLength::PercentageLength,100), - QTextLength(QTextLength::VariableLength,0)}); tableFormat.setBorderStyle(QTextFrameFormat::BorderStyle_None); + tableFormat.setCellSpacing(2); + tableFormat.setWidth(QTextLength(QTextLength::PercentageLength,100)); chatTextTable->setFormat(tableFormat); - chatTextTable->format().setCellSpacing(2); - chatTextTable->format().setWidth(QTextLength(QTextLength::PercentageLength,100)); + setNameColWidth(100); // nameFormat.setAlignment(Qt::AlignRight); // nameFormat.setNonBreakableLines(true); @@ -135,3 +133,14 @@ void ChatAreaWidget::checkSlider() QScrollBar* scroll = verticalScrollBar(); lockSliderToBottom = scroll && scroll->value() == scroll->maximum(); } + +void ChatAreaWidget::setNameColWidth(int w) +{ + nameWidth = w; + + QTextTableFormat tableFormat = chatTextTable->format(); + tableFormat.setColumnWidthConstraints({QTextLength(QTextLength::FixedLength, 100), + QTextLength(QTextLength::PercentageLength, 100), + QTextLength(QTextLength::FixedLength, 40)}); + chatTextTable->setFormat(tableFormat); +} diff --git a/widget/chatareawidget.h b/widget/chatareawidget.h index c30b12c61..05d41de4e 100644 --- a/widget/chatareawidget.h +++ b/widget/chatareawidget.h @@ -31,6 +31,9 @@ public: virtual ~ChatAreaWidget(); void insertMessage(ChatAction *msgAction); + int nameColWidth() {return nameWidth;} + void setNameColWidth(int w); + signals: void onFileTranfertInterract(QString widgetName, QString buttonName); @@ -47,6 +50,7 @@ private: QList messages; bool lockSliderToBottom; int sliderPosition; + int nameWidth; QTextTable *chatTextTable; QTextBlockFormat nameFormat, dateFormat; }; diff --git a/widget/form/chatform.cpp b/widget/form/chatform.cpp index a200eff08..9c57f0d88 100644 --- a/widget/form/chatform.cpp +++ b/widget/form/chatform.cpp @@ -125,7 +125,7 @@ void ChatForm::startFileSend(ToxFile file) name = ""; previousName = Widget::getInstance()->getUsername(); - chatWidget->insertMessage(new FileTransferAction(fileTrans, name, QTime::currentTime().toString("hh:mm"), true)); + chatWidget->insertMessage(new FileTransferAction(fileTrans, getElidedName(name), QTime::currentTime().toString("hh:mm"), true)); } void ChatForm::onFileRecvRequest(ToxFile file) @@ -156,7 +156,7 @@ void ChatForm::onFileRecvRequest(ToxFile file) name = ""; previousName = f->getName(); - chatWidget->insertMessage(new FileTransferAction(fileTrans, name, QTime::currentTime().toString("hh:mm"), false)); + chatWidget->insertMessage(new FileTransferAction(fileTrans, getElidedName(name), QTime::currentTime().toString("hh:mm"), false)); } void ChatForm::onAvInvite(int FriendId, int CallId, bool video) diff --git a/widget/form/genericchatform.cpp b/widget/form/genericchatform.cpp index a10fe0c83..c992ba563 100644 --- a/widget/form/genericchatform.cpp +++ b/widget/form/genericchatform.cpp @@ -169,7 +169,7 @@ void GenericChatForm::addMessage(QString author, QString message, QDateTime date if (previousName == author) chatWidget->insertMessage(new MessageAction("", message, date, isMe)); - else chatWidget->insertMessage(new MessageAction(author , message, date, isMe)); + else chatWidget->insertMessage(new MessageAction(getElidedName(author) , message, date, isMe)); previousName = author; } @@ -212,3 +212,12 @@ void GenericChatForm::addSystemInfoMessage(const QString &message, const QString chatWidget->insertMessage(new SystemMessageAction(message, type, date)); } + +QString GenericChatForm::getElidedName(const QString& name) +{ + QFont font; + font.setBold(true); + QFontMetrics fm(font); + + return fm.elidedText(name, Qt::ElideRight, chatWidget->nameColWidth()); +} diff --git a/widget/form/genericchatform.h b/widget/form/genericchatform.h index d45bf1072..2111bcdf9 100644 --- a/widget/form/genericchatform.h +++ b/widget/form/genericchatform.h @@ -60,6 +60,8 @@ protected slots: void onEmoteInsertRequested(QString str); protected: + QString getElidedName(const QString& name); + CroppingLabel *nameLabel; MaskablePixmapWidget *avatar; QWidget *headWidget; From 7735973d9467c6d95dd6fbd28ab487350396b84e Mon Sep 17 00:00:00 2001 From: dubslow Date: Sun, 28 Sep 2014 12:57:27 -0500 Subject: [PATCH 106/205] remove duplicate code --- core.cpp | 4 ++-- core.h | 3 --- widget/widget.cpp | 20 -------------------- widget/widget.h | 2 -- 4 files changed, 2 insertions(+), 27 deletions(-) diff --git a/core.cpp b/core.cpp index 1b04c16ac..1b3eb4fc4 100644 --- a/core.cpp +++ b/core.cpp @@ -1014,7 +1014,7 @@ void Core::loadFriends() if (nameSize > 0) { uint8_t *name = new uint8_t[nameSize]; if (tox_get_name(tox, ids[i], name) == nameSize) { - emit friendUsernameLoaded(ids[i], CString::toString(name, nameSize)); + emit friendUsernameChanged(ids[i], CString::toString(name, nameSize)); } delete[] name; } @@ -1023,7 +1023,7 @@ void Core::loadFriends() if (statusMessageSize > 0) { uint8_t *statusMessage = new uint8_t[statusMessageSize]; if (tox_get_status_message(tox, ids[i], statusMessage, statusMessageSize) == statusMessageSize) { - emit friendStatusMessageLoaded(ids[i], CString::toString(statusMessage, statusMessageSize)); + emit friendStatusMessageChanged(ids[i], CString::toString(statusMessage, statusMessageSize)); } delete[] statusMessage; } diff --git a/core.h b/core.h index 253ccb401..b1425c59e 100644 --- a/core.h +++ b/core.h @@ -109,9 +109,6 @@ signals: void friendAvatarChanged(int friendId, const QPixmap& pic); void friendAvatarRemoved(int friendId); - void friendStatusMessageLoaded(int friendId, const QString& message); - void friendUsernameLoaded(int friendId, const QString& username); - void friendAddressGenerated(const QString& friendAddress); void friendRemoved(int friendId); diff --git a/widget/widget.cpp b/widget/widget.cpp index 7c38847a6..5ee81d758 100644 --- a/widget/widget.cpp +++ b/widget/widget.cpp @@ -198,8 +198,6 @@ Widget::Widget(QWidget *parent) connect(core, &Core::friendUsernameChanged, this, &Widget::onFriendUsernameChanged); connect(core, &Core::friendStatusChanged, this, &Widget::onFriendStatusChanged); connect(core, &Core::friendStatusMessageChanged, this, &Widget::onFriendStatusMessageChanged); - connect(core, &Core::friendUsernameLoaded, this, &Widget::onFriendUsernameLoaded); - connect(core, &Core::friendStatusMessageLoaded, this, &Widget::onFriendStatusMessageLoaded); connect(core, &Core::friendRequestReceived, this, &Widget::onFriendRequestReceived); connect(core, &Core::friendMessageReceived, this, &Widget::onFriendMessageReceived); connect(core, &Core::groupInviteReceived, this, &Widget::onGroupInviteReceived); @@ -525,24 +523,6 @@ void Widget::onFriendUsernameChanged(int friendId, const QString& username) f->setName(username); } -void Widget::onFriendStatusMessageLoaded(int friendId, const QString& message) -{ - Friend* f = FriendList::findFriend(friendId); - if (!f) - return; - - f->setStatusMessage(message); -} - -void Widget::onFriendUsernameLoaded(int friendId, const QString& username) -{ - Friend* f = FriendList::findFriend(friendId); - if (!f) - return; - - f->setName(username); -} - void Widget::onChatroomWidgetClicked(GenericChatroomWidget *widget) { hideMainForms(); diff --git a/widget/widget.h b/widget/widget.h index 5ec25b501..5141e49f0 100644 --- a/widget/widget.h +++ b/widget/widget.h @@ -92,8 +92,6 @@ private slots: void onFriendStatusChanged(int friendId, Status status); void onFriendStatusMessageChanged(int friendId, const QString& message); void onFriendUsernameChanged(int friendId, const QString& username); - void onFriendStatusMessageLoaded(int friendId, const QString& message); - void onFriendUsernameLoaded(int friendId, const QString& username); void onChatroomWidgetClicked(GenericChatroomWidget *); void onFriendMessageReceived(int friendId, const QString& message); void onFriendRequestReceived(const QString& userId, const QString& message); From 84f56b81a728effcfa9531704194a79c53336252 Mon Sep 17 00:00:00 2001 From: dubslow Date: Sun, 28 Sep 2014 13:09:10 -0500 Subject: [PATCH 107/205] fixes #331, remove special chars --- widget/widget.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/widget/widget.cpp b/widget/widget.cpp index 5ee81d758..2b322eecd 100644 --- a/widget/widget.cpp +++ b/widget/widget.cpp @@ -511,7 +511,9 @@ void Widget::onFriendStatusMessageChanged(int friendId, const QString& message) if (!f) return; - f->setStatusMessage(message); + QString str = message; str.replace('\n', ' '); + str.remove('\r'); str.remove(QChar((char)0)); // null terminator... + f->setStatusMessage(str); } void Widget::onFriendUsernameChanged(int friendId, const QString& username) @@ -520,7 +522,9 @@ void Widget::onFriendUsernameChanged(int friendId, const QString& username) if (!f) return; - f->setName(username); + QString str = username; str.replace('\n', ' '); + str.remove('\r'); str.remove(QChar((char)0)); // null terminator... + f->setName(str); } void Widget::onChatroomWidgetClicked(GenericChatroomWidget *widget) From c037edd033cfc654b3dcb00930c74d5aa489d25f Mon Sep 17 00:00:00 2001 From: dubslow Date: Sun, 28 Sep 2014 18:08:07 -0500 Subject: [PATCH 108/205] work torwards #340, CAUTION spams bootstrapDht() until connection is confirmed, so it's not quite right... --- core.cpp | 132 ++++++++++++++++++++++---------------------------- core.h | 4 +- coredefines.h | 2 - 3 files changed, 59 insertions(+), 79 deletions(-) diff --git a/core.cpp b/core.cpp index 1b3eb4fc4..8693d77de 100644 --- a/core.cpp +++ b/core.cpp @@ -49,15 +49,9 @@ Core::Core(Camera* cam, QThread *coreThread) : toxTimer = new QTimer(this); toxTimer->setSingleShot(true); - //saveTimer = new QTimer(this); - //saveTimer->start(TOX_SAVE_INTERVAL); - bootstrapTimer = new QTimer(this); - bootstrapTimer->start(TOX_BOOTSTRAP_INTERVAL); connect(toxTimer, &QTimer::timeout, this, &Core::process); - //connect(saveTimer, &QTimer::timeout, this, &Core::saveConfiguration); //Disable save timer in favor of saving on events //connect(fileTimer, &QTimer::timeout, this, &Core::fileHeartbeat); - connect(bootstrapTimer, &QTimer::timeout, this, &Core::onBootstrapTimer); - connect(&Settings::getInstance(), &Settings::dhtServerListChanged, this, &Core::bootstrapDht); + connect(&Settings::getInstance(), &Settings::dhtServerListChanged, this, &Core::process); connect(this, SIGNAL(fileTransferFinished(ToxFile)), this, SLOT(onFileTransferFinished(ToxFile))); for (int i=0; istart(tox_do_interval(tox)); + TOX_DO_INTERVAL = tox_do_interval(tox); + + process(); // starts its own timer } -void Core::onBootstrapTimer() +void Core::process() { if (!tox) return; - if(!tox_isconnected(tox)) + + tox_do(tox); +#ifdef DEBUG + //we want to see the debug messages immediately + fflush(stdout); +#endif + if (!checkConnection()) bootstrapDht(); + + toxTimer->start(TOX_DO_INTERVAL); +} + +bool Core::checkConnection() +{ + static bool isConnected = false; + bool toxConnected = tox_isconnected(tox); + + if (toxConnected && !isConnected) { + qDebug() << "Core: Connected to DHT"; + emit connected(); + isConnected = true; + } else if (!toxConnected && isConnected) { + qDebug() << "Core: Disconnected to DHT"; + emit disconnected(); + isConnected = false; + } + return isConnected; +} + +void Core::bootstrapDht() +{ + const Settings& s = Settings::getInstance(); + QList dhtServerList = s.getDhtServerList(); + + int listSize = dhtServerList.size(); + static int j = qrand() % listSize; + + qDebug() << "Core: Bootstraping to the DHT ..."; + + int i=0; + while (i < 3) + { + const Settings::DhtServer& dhtServer = dhtServerList[j % listSize]; + if (tox_bootstrap_from_address(tox, dhtServer.address.toLatin1().data(), + dhtServer.port, CUserId(dhtServer.userId).data()) == 1) + qDebug() << QString("Core: Bootstraping from ")+dhtServer.name+QString(", addr ")+dhtServer.address.toLatin1().data() + +QString(", port ")+QString().setNum(dhtServer.port); + else + qDebug() << "Core: Error bootstraping from "+dhtServer.name; + + j++; + i++; + } } void Core::onFriendRequest(Tox*/* tox*/, const uint8_t* cUserId, const uint8_t* cMessage, uint16_t cMessageSize, void* core) @@ -861,69 +906,6 @@ void Core::onFileTransferFinished(ToxFile file) emit fileDownloadFinished(file.filePath); } -void Core::bootstrapDht() -{ - const Settings& s = Settings::getInstance(); - QList dhtServerList = s.getDhtServerList(); - - int listSize = dhtServerList.size(); - static int j = qrand() % listSize, n=0; - - // We couldn't connect after trying 6 different nodes, let's try something else - if (n>3) - { - qDebug() << "Core: We're having trouble connecting to the DHT, slowing down"; - bootstrapTimer->setInterval(TOX_BOOTSTRAP_INTERVAL*(n-1)); - } - else - qDebug() << "Core: Connecting to the DHT ..."; - - int i=0; - while (i < (2 - (n>3))) - { - const Settings::DhtServer& dhtServer = dhtServerList[j % listSize]; - if (tox_bootstrap_from_address(tox, dhtServer.address.toLatin1().data(), - dhtServer.port, CUserId(dhtServer.userId).data()) == 1) - qDebug() << QString("Core: Bootstraping from ")+dhtServer.name+QString(", addr ")+dhtServer.address.toLatin1().data() - +QString(", port ")+QString().setNum(dhtServer.port); - else - qDebug() << "Core: Error bootstraping from "+dhtServer.name; - - tox_do(tox); - j++; - i++; - n++; - } -} - -void Core::process() -{ - tox_do(tox); -#ifdef DEBUG - //we want to see the debug messages immediately - fflush(stdout); -#endif - checkConnection(); - //int toxInterval = tox_do_interval(tox); - //qDebug() << QString("Tox interval %1").arg(toxInterval); - toxTimer->start(50); -} - -void Core::checkConnection() -{ - static bool isConnected = false; - - if (tox_isconnected(tox) && !isConnected) { - qDebug() << "Core: Connected to DHT"; - emit connected(); - isConnected = true; - } else if (!tox_isconnected(tox) && isConnected) { - qDebug() << "Core: Disconnected to DHT"; - emit disconnected(); - isConnected = false; - } -} - void Core::loadConfiguration() { QString path = QDir(Settings::getSettingsDirPath()).filePath(CONFIG_FILE_NAME); diff --git a/core.h b/core.h index b1425c59e..f247dd59b 100644 --- a/core.h +++ b/core.h @@ -206,8 +206,7 @@ private: static void playCallVideo(ToxAv* toxav, int32_t callId, vpx_image_t* img, void *user_data); void sendCallVideo(int callId); - void checkConnection(); - void onBootstrapTimer(); + bool checkConnection(); void loadConfiguration(); void loadFriends(); @@ -236,6 +235,7 @@ private: static const int videobufsize; static uint8_t* videobuf; static int videoBusyness; // Used to know when to drop frames + int TOX_DO_INTERVAL; static ALCdevice* alOutDev, *alInDev; static ALCcontext* alContext; diff --git a/coredefines.h b/coredefines.h index cb6fcffed..e2c71b8d4 100644 --- a/coredefines.h +++ b/coredefines.h @@ -3,9 +3,7 @@ #define TOXAV_MAX_CALLS 16 #define GROUPCHAT_MAX_SIZE 32 -#define TOX_SAVE_INTERVAL 30*1000 #define TOX_FILE_INTERVAL 0 -#define TOX_BOOTSTRAP_INTERVAL 5*1000 #define TOXAV_RINGING_TIME 15 // TODO: Put that in the settings From d9a315c5896e5d8951dc675aededb278bc17ddc4 Mon Sep 17 00:00:00 2001 From: dubslow Date: Sun, 28 Sep 2014 18:21:08 -0500 Subject: [PATCH 109/205] fix #340 --- core.cpp | 18 ++++++++++++------ core.h | 1 - 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/core.cpp b/core.cpp index 8693d77de..84265dd10 100644 --- a/core.cpp +++ b/core.cpp @@ -216,8 +216,6 @@ void Core::start() } else qDebug() << "Core: Error loading self avatar"; - - TOX_DO_INTERVAL = tox_do_interval(tox); process(); // starts its own timer } @@ -227,15 +225,23 @@ void Core::process() if (!tox) return; + static int retries = 0; tox_do(tox); + #ifdef DEBUG //we want to see the debug messages immediately fflush(stdout); #endif - if (!checkConnection()) - bootstrapDht(); - toxTimer->start(TOX_DO_INTERVAL); + if (checkConnection()) + retries = 0; + else if (retries < 2) + { + retries++; + bootstrapDht(); + } + + toxTimer->start(tox_do_interval(tox)); } bool Core::checkConnection() @@ -266,7 +272,7 @@ void Core::bootstrapDht() qDebug() << "Core: Bootstraping to the DHT ..."; int i=0; - while (i < 3) + while (i < 2) { const Settings::DhtServer& dhtServer = dhtServerList[j % listSize]; if (tox_bootstrap_from_address(tox, dhtServer.address.toLatin1().data(), diff --git a/core.h b/core.h index f247dd59b..c7227831e 100644 --- a/core.h +++ b/core.h @@ -235,7 +235,6 @@ private: static const int videobufsize; static uint8_t* videobuf; static int videoBusyness; // Used to know when to drop frames - int TOX_DO_INTERVAL; static ALCdevice* alOutDev, *alInDev; static ALCcontext* alContext; From 940cdfebba3c48d421808534cd9dfbb739175a07 Mon Sep 17 00:00:00 2001 From: dubslow Date: Sun, 28 Sep 2014 20:54:28 -0500 Subject: [PATCH 110/205] implement avatar hash caching instead of getting full avatar each time --- core.cpp | 28 ++++++++++++++++++++-------- settings.cpp | 25 ++++++++++++++++++++++++- settings.h | 3 +++ 3 files changed, 47 insertions(+), 9 deletions(-) diff --git a/core.cpp b/core.cpp index 1b3eb4fc4..403b3e8b9 100644 --- a/core.cpp +++ b/core.cpp @@ -280,7 +280,7 @@ void Core::onUserStatusChanged(Tox*/* tox*/, int friendId, uint8_t userstatus, v } if (status == Status::Online || status == Status::Away) - tox_request_avatar_data(static_cast(core)->tox, friendId); + tox_request_avatar_info(static_cast(core)->tox, friendId); emit static_cast(core)->friendStatusChanged(friendId, status); } @@ -453,28 +453,40 @@ void Core::onFileDataCallback(Tox*, int32_t friendnumber, uint8_t filenumber, co } void Core::onAvatarInfoCallback(Tox*, int32_t friendnumber, uint8_t format, - uint8_t *, void* core) + uint8_t* hash, void* _core) { - qDebug() << "Core: Got avatar info from "<(_core); if (format == TOX_AVATAR_FORMAT_NONE) - emit static_cast(core)->friendAvatarRemoved(friendnumber); + { + qDebug() << "Core: Got null avatar info from" << friendnumber; + emit core->friendAvatarRemoved(friendnumber); + } else - tox_request_avatar_data(static_cast(core)->tox, friendnumber); + { + QByteArray oldHash = Settings::getInstance().getAvatarHash(core->getFriendAddress(friendnumber)); + if (QByteArray((char*)hash, TOX_HASH_LENGTH) != oldHash) // comparison failed miserably if I didn't convert hash to QByteArray + { + qDebug() << "Core: got different avatar hash from" << friendnumber; + tox_request_avatar_data(core->tox, friendnumber); + } + else + qDebug() << "Core: Got old avatar info from" << friendnumber; + } } void Core::onAvatarDataCallback(Tox*, int32_t friendnumber, uint8_t, - uint8_t *, uint8_t *data, uint32_t datalen, void *core) + uint8_t *hash, uint8_t *data, uint32_t datalen, void *core) { QPixmap pic; pic.loadFromData((uchar*)data, datalen); if (pic.isNull()) - qDebug() << "Core: Got invalid avatar data from "<(core)->getFriendAddress(friendnumber)); + Settings::getInstance().saveAvatarHash(QByteArray((char*)hash, TOX_HASH_LENGTH), static_cast(core)->getFriendAddress(friendnumber)); emit static_cast(core)->friendAvatarChanged(friendnumber, pic); } } diff --git a/settings.cpp b/settings.cpp index 3e9f33426..31cbd158e 100644 --- a/settings.cpp +++ b/settings.cpp @@ -280,12 +280,35 @@ QPixmap Settings::getSavedAvatar(const QString &ownerId) void Settings::saveAvatar(QPixmap& pic, const QString& ownerId) { QDir dir(getSettingsDirPath()); - dir.mkdir("avatars/"); // remove this in a week or two hopefully + dir.mkdir("avatars/"); // ignore nospam (good idea, and also the addFriend funcs which call getAvatar don't have it) QString filePath = dir.filePath("avatars/"+ownerId.left(64)+".png"); pic.save(filePath, "png"); } +void Settings::saveAvatarHash(const QByteArray& hash, const QString& ownerId) +{ + QDir dir(getSettingsDirPath()); + dir.mkdir("avatars/"); + QFile file(dir.filePath("avatars/"+ownerId.left(64)+".hash")); + if (!file.open(QIODevice::WriteOnly)) + return; + file.write(hash); + file.close(); +} + +QByteArray Settings::getAvatarHash(const QString& ownerId) +{ + QDir dir(getSettingsDirPath()); + dir.mkdir("avatars/"); + QFile file(dir.filePath("avatars/"+ownerId.left(64)+".hash")); + if (!file.open(QIODevice::ReadOnly)) + return QByteArray(); + QByteArray out = file.readAll(); + file.close(); + return out; +} + const QList& Settings::getDhtServerList() const { return dhtServerList; diff --git a/settings.h b/settings.h index b796211cb..9f379e886 100644 --- a/settings.h +++ b/settings.h @@ -61,6 +61,9 @@ public: QPixmap getSavedAvatar(const QString& ownerId); void saveAvatar(QPixmap& pic, const QString& ownerId); + QByteArray getAvatarHash(const QString& ownerId); + void saveAvatarHash(const QByteArray& hash, const QString& ownerId); + // Assume all widgets have unique names // Don't use it to save every single thing you want to save, use it // for some general purpose widgets, such as MainWindows or Splitters, From a4d42a713621344a58b1cd2aad02aface0dd422d Mon Sep 17 00:00:00 2001 From: dubslow Date: Sun, 28 Sep 2014 23:10:04 -0500 Subject: [PATCH 111/205] change file eta to be overall average handles jitter much better --- filetransferinstance.cpp | 19 ++++++++++--------- filetransferinstance.h | 2 +- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/filetransferinstance.cpp b/filetransferinstance.cpp index f8b10ecc8..d55de0bf4 100644 --- a/filetransferinstance.cpp +++ b/filetransferinstance.cpp @@ -28,7 +28,7 @@ uint FileTransferInstance::Idconter = 0; FileTransferInstance::FileTransferInstance(ToxFile File) - : lastUpdate{QDateTime::currentDateTime()}, lastBytesSent{0}, + : lastBytesSent{0}, fileNum{File.fileNum}, friendId{File.friendId}, direction{File.direction} { id = Idconter++; @@ -72,16 +72,16 @@ void FileTransferInstance::onFileTransferInfo(int FriendId, int FileNum, int64_t // state = tsProcessing; QDateTime newtime = QDateTime::currentDateTime(); - int timediff = lastUpdate.secsTo(newtime); + int timediff = started.secsTo(newtime); if (timediff <= 0) return; - qint64 diff = BytesSent - lastBytesSent; - if (diff < 0) + qint64 totalbytes = BytesSent + lastBytesSent; // bytes sent so far + if (totalbytes < 0) { qWarning() << "FileTransferInstance::onFileTransferInfo: Negative transfer speed !"; - diff = 0; + totalbytes = 0; } - long rawspeed = diff / timediff; + long rawspeed = totalbytes / timediff; speed = getHumanReadableSize(rawspeed)+"/s"; size = getHumanReadableSize(Filesize); totalBytes = Filesize; @@ -91,8 +91,7 @@ void FileTransferInstance::onFileTransferInfo(int FriendId, int FileNum, int64_t QTime etaTime(0,0); etaTime = etaTime.addSecs(etaSecs); eta = etaTime.toString("mm:ss"); - lastUpdate = newtime; - lastBytesSent = BytesSent; + lastBytesSent = totalbytes; emit stateUpdated(); } @@ -197,7 +196,7 @@ void FileTransferInstance::acceptRecvRequest() QString path; while (true) { - path = QFileDialog::getSaveFileName(0, tr("Save a file","Title of the file saving dialog"), QDir::current().filePath(filename)); + path = QFileDialog::getSaveFileName(0, tr("Save a file","Title of the file saving dialog"), QDir::home().filePath(filename)); if (path.isEmpty()) return; else @@ -217,6 +216,8 @@ void FileTransferInstance::acceptRecvRequest() Core::getInstance()->acceptFileRecvRequest(friendId, fileNum, path); state = tsProcessing; + started = QDateTime::currentDateTime(); + emit stateUpdated(); } diff --git a/filetransferinstance.h b/filetransferinstance.h index fb54fd8f6..d0b766a13 100644 --- a/filetransferinstance.h +++ b/filetransferinstance.h @@ -73,7 +73,7 @@ private: QImage pic; QString filename, size, speed, eta; QString filenameElided; - QDateTime lastUpdate; + QDateTime started; long long lastBytesSent, totalBytes; int fileNum; int friendId; From 8a1c912da3850d4aad42b40ff68d5f827f5e3471 Mon Sep 17 00:00:00 2001 From: dubslow Date: Sun, 28 Sep 2014 23:16:11 -0500 Subject: [PATCH 112/205] mv some files, clean up top level folder --- cdata.cpp => misc/cdata.cpp | 0 cdata.h => misc/cdata.h | 0 cstring.cpp => misc/cstring.cpp | 0 cstring.h => misc/cstring.h | 0 settings.cpp => misc/settings.cpp | 0 settings.h => misc/settings.h | 0 smileypack.cpp => misc/smileypack.cpp | 0 smileypack.h => misc/smileypack.h | 0 style.cpp => misc/style.cpp | 0 style.h => misc/style.h | 0 10 files changed, 0 insertions(+), 0 deletions(-) rename cdata.cpp => misc/cdata.cpp (100%) rename cdata.h => misc/cdata.h (100%) rename cstring.cpp => misc/cstring.cpp (100%) rename cstring.h => misc/cstring.h (100%) rename settings.cpp => misc/settings.cpp (100%) rename settings.h => misc/settings.h (100%) rename smileypack.cpp => misc/smileypack.cpp (100%) rename smileypack.h => misc/smileypack.h (100%) rename style.cpp => misc/style.cpp (100%) rename style.h => misc/style.h (100%) diff --git a/cdata.cpp b/misc/cdata.cpp similarity index 100% rename from cdata.cpp rename to misc/cdata.cpp diff --git a/cdata.h b/misc/cdata.h similarity index 100% rename from cdata.h rename to misc/cdata.h diff --git a/cstring.cpp b/misc/cstring.cpp similarity index 100% rename from cstring.cpp rename to misc/cstring.cpp diff --git a/cstring.h b/misc/cstring.h similarity index 100% rename from cstring.h rename to misc/cstring.h diff --git a/settings.cpp b/misc/settings.cpp similarity index 100% rename from settings.cpp rename to misc/settings.cpp diff --git a/settings.h b/misc/settings.h similarity index 100% rename from settings.h rename to misc/settings.h diff --git a/smileypack.cpp b/misc/smileypack.cpp similarity index 100% rename from smileypack.cpp rename to misc/smileypack.cpp diff --git a/smileypack.h b/misc/smileypack.h similarity index 100% rename from smileypack.h rename to misc/smileypack.h diff --git a/style.cpp b/misc/style.cpp similarity index 100% rename from style.cpp rename to misc/style.cpp diff --git a/style.h b/misc/style.h similarity index 100% rename from style.h rename to misc/style.h From 25a0a90cf73e05aabe32b6b9edb1801a166efe3f Mon Sep 17 00:00:00 2001 From: krepa098 Date: Mon, 29 Sep 2014 10:38:31 +0200 Subject: [PATCH 113/205] fix #334 --- widget/friendwidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/widget/friendwidget.cpp b/widget/friendwidget.cpp index 5bce871f7..ad16ac75c 100644 --- a/widget/friendwidget.cpp +++ b/widget/friendwidget.cpp @@ -210,7 +210,7 @@ void FriendWidget::onAvatarRemoved(int FriendId) return; isDefaultAvatar = true; - avatar->setPixmap(QPixmap(":img/contact.png")); + avatar->setPixmap(QPixmap(":img/contact_dark.png")); } void FriendWidget::mousePressEvent(QMouseEvent *ev) From dbeccd36f9d185946464edc676ca9f235f6bfaa7 Mon Sep 17 00:00:00 2001 From: apprb Date: Mon, 29 Sep 2014 19:43:14 +0700 Subject: [PATCH 114/205] FileTransferInstance: unification of preview images function --- filetransferinstance.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/filetransferinstance.cpp b/filetransferinstance.cpp index f8b10ecc8..0799c9615 100644 --- a/filetransferinstance.cpp +++ b/filetransferinstance.cpp @@ -24,6 +24,7 @@ #include #define CONTENT_WIDTH 250 +#define MAX_PREVIEW_SIZE 25*1024*1024 uint FileTransferInstance::Idconter = 0; @@ -44,13 +45,17 @@ FileTransferInstance::FileTransferInstance(ToxFile File) size = getHumanReadableSize(File.filesize); speed = "0B/s"; eta = "00:00"; + if (File.direction == ToxFile::SENDING) { - QImage preview; - File.file->seek(0); - if (preview.loadFromData(File.file->readAll())) + if (File.file->size() <= MAX_PREVIEW_SIZE) { - pic = preview.scaledToHeight(50); + QImage preview; + File.file->seek(0); + if (preview.loadFromData(File.file->readAll())) + { + pic = preview.scaledToHeight(50); + } } File.file->seek(0); } @@ -116,7 +121,7 @@ void FileTransferInstance::onFileTransferFinished(ToxFile File) { QImage preview; QFile previewFile(File.filePath); - if (previewFile.open(QIODevice::ReadOnly) && previewFile.size() <= 1024*1024*25) // Don't preview big (>25MiB) images + if (previewFile.open(QIODevice::ReadOnly) && previewFile.size() <= MAX_PREVIEW_SIZE) // Don't preview big (>25MiB) images { if (preview.loadFromData(previewFile.readAll())) { From 4dfa5a45c4b3973f47803a36f7f78e54c1eb8972 Mon Sep 17 00:00:00 2001 From: apprb Date: Mon, 29 Sep 2014 20:59:07 +0700 Subject: [PATCH 115/205] Core::onFileControlCallback: handle TOX_FILECONTROL_RESUME_BROKEN request --- core.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/core.cpp b/core.cpp index 1b3eb4fc4..0361535a9 100644 --- a/core.cpp +++ b/core.cpp @@ -328,7 +328,7 @@ void Core::onFileSendRequestCallback(Tox*, int32_t friendnumber, uint8_t filenum emit static_cast(core)->fileReceiveRequested(fileRecvQueue.last()); } void Core::onFileControlCallback(Tox* tox, int32_t friendnumber, uint8_t receive_send, uint8_t filenumber, - uint8_t control_type, const uint8_t*, uint16_t, void *core) + uint8_t control_type, const uint8_t* data, uint16_t, void *core) { ToxFile* file{nullptr}; if (receive_send == 1) @@ -421,6 +421,21 @@ void Core::onFileControlCallback(Tox* tox, int32_t friendnumber, uint8_t receive { emit static_cast(core)->fileTransferRemotePausedUnpaused(*file, true); } + else if (receive_send == 1 && control_type == TOX_FILECONTROL_RESUME_BROKEN) + { + qDebug() << "Core::onFileControlCallback: TOX_FILECONTROL_RESUME_BROKEN"; + uint64_t resumePos = *(uint64_t*)data; + + if (resumePos >= file->filesize) + { + qWarning() << "Core::onFileControlCallback: invalid resume position"; + tox_file_send_control(tox, file->friendId, 0, file->fileNum, TOX_FILECONTROL_KILL, nullptr, 0); // don't sure about it + return; + } + + file->bytesSent = resumePos; + tox_file_send_control(tox, file->friendId, 0, file->fileNum, TOX_FILECONTROL_ACCEPT, nullptr, 0); + } else { qDebug() << QString("Core: File control callback, receive_send=%1, control_type=%2") From 575cac1fc70449d888e1ea4dcc8c692d8012f222 Mon Sep 17 00:00:00 2001 From: apprb Date: Mon, 29 Sep 2014 23:14:19 +0700 Subject: [PATCH 116/205] Core: emit TOX_FILECONTROL_RESUME_BROKEN request (base functionality) --- core.cpp | 32 ++++++++++++++++++++++++++++++-- core.h | 1 + corestructs.h | 3 ++- filetransferinstance.h | 2 +- 4 files changed, 34 insertions(+), 4 deletions(-) diff --git a/core.cpp b/core.cpp index 0361535a9..2662b4fd8 100644 --- a/core.cpp +++ b/core.cpp @@ -291,6 +291,34 @@ void Core::onConnectionStatusChanged(Tox*/* tox*/, int friendId, uint8_t status, emit static_cast(core)->friendStatusChanged(friendId, friendStatus); if (friendStatus == Status::Offline) { static_cast(core)->checkLastOnline(friendId); + + for (ToxFile& f : fileSendQueue) + { + if (f.friendId == friendId && f.status == ToxFile::TRANSMITTING) + { + qDebug() << "friendId: set broken"; + f.status = ToxFile::BROKEN; + emit static_cast(core)->fileTransferBrokenUnbroken(f, true); + } + } + for (ToxFile& f : fileRecvQueue) + { + if (f.friendId == friendId && f.status == ToxFile::TRANSMITTING) + { + qDebug() << "friendId: set broken"; + f.status = ToxFile::BROKEN; + emit static_cast(core)->fileTransferBrokenUnbroken(f, true); + } + } + } else { + for (ToxFile& f : fileRecvQueue) + { + if (f.friendId == friendId && f.status == ToxFile::BROKEN) + { + tox_file_send_control(static_cast(core)->tox, friendId, 1, f.fileNum, TOX_FILECONTROL_RESUME_BROKEN, (const uint8_t*)(&f.bytesSent), sizeof(uint64_t)); + emit static_cast(core)->fileTransferBrokenUnbroken(f, false); + } + } } } @@ -424,7 +452,7 @@ void Core::onFileControlCallback(Tox* tox, int32_t friendnumber, uint8_t receive else if (receive_send == 1 && control_type == TOX_FILECONTROL_RESUME_BROKEN) { qDebug() << "Core::onFileControlCallback: TOX_FILECONTROL_RESUME_BROKEN"; - uint64_t resumePos = *(uint64_t*)data; + uint64_t resumePos = *(const uint64_t*)(data); if (resumePos >= file->filesize) { @@ -655,7 +683,7 @@ void Core::pauseResumeFileRecv(int friendId, int fileNum) tox_file_send_control(tox, file->friendId, 1, file->fileNum, TOX_FILECONTROL_ACCEPT, nullptr, 0); } else - qWarning() << "Core::pauseResumeFileRecv: File is stopped"; + qWarning() << "Core::pauseResumeFileRecv: File is stopped or broken"; } void Core::cancelFileSend(int friendId, int fileNum) diff --git a/core.h b/core.h index b1425c59e..fbaca60da 100644 --- a/core.h +++ b/core.h @@ -150,6 +150,7 @@ signals: void fileTransferPaused(int FriendId, int FileNum, ToxFile::FileDirection direction); void fileTransferInfo(int FriendId, int FileNum, int64_t Filesize, int64_t BytesSent, ToxFile::FileDirection direction); void fileTransferRemotePausedUnpaused(ToxFile file, bool paused); + void fileTransferBrokenUnbroken(ToxFile file, bool broken); void fileSendFailed(int FriendId, const QString& fname); diff --git a/corestructs.h b/corestructs.h index a2bb6f31f..00da8a6a5 100644 --- a/corestructs.h +++ b/corestructs.h @@ -50,7 +50,8 @@ struct ToxFile { STOPPED, PAUSED, - TRANSMITTING + TRANSMITTING, + BROKEN }; enum FileDirection : bool diff --git a/filetransferinstance.h b/filetransferinstance.h index fb54fd8f6..23f75f282 100644 --- a/filetransferinstance.h +++ b/filetransferinstance.h @@ -28,7 +28,7 @@ class FileTransferInstance : public QObject { Q_OBJECT public: - enum TransfState {tsPending, tsProcessing, tsPaused, tsFinished, tsCanceled}; + enum TransfState {tsPending, tsProcessing, tsPaused, tsFinished, tsCanceled, tsBroken}; public: explicit FileTransferInstance(ToxFile File); From 76f7df313543730e736bfd2cc2ebacb22dbcacac Mon Sep 17 00:00:00 2001 From: apprb Date: Mon, 29 Sep 2014 23:36:42 +0700 Subject: [PATCH 117/205] cleanup --- core.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/core.cpp b/core.cpp index 2662b4fd8..f1de8614f 100644 --- a/core.cpp +++ b/core.cpp @@ -296,7 +296,6 @@ void Core::onConnectionStatusChanged(Tox*/* tox*/, int friendId, uint8_t status, { if (f.friendId == friendId && f.status == ToxFile::TRANSMITTING) { - qDebug() << "friendId: set broken"; f.status = ToxFile::BROKEN; emit static_cast(core)->fileTransferBrokenUnbroken(f, true); } @@ -305,7 +304,6 @@ void Core::onConnectionStatusChanged(Tox*/* tox*/, int friendId, uint8_t status, { if (f.friendId == friendId && f.status == ToxFile::TRANSMITTING) { - qDebug() << "friendId: set broken"; f.status = ToxFile::BROKEN; emit static_cast(core)->fileTransferBrokenUnbroken(f, true); } @@ -315,7 +313,8 @@ void Core::onConnectionStatusChanged(Tox*/* tox*/, int friendId, uint8_t status, { if (f.friendId == friendId && f.status == ToxFile::BROKEN) { - tox_file_send_control(static_cast(core)->tox, friendId, 1, f.fileNum, TOX_FILECONTROL_RESUME_BROKEN, (const uint8_t*)(&f.bytesSent), sizeof(uint64_t)); + qDebug() << QString("Core::onConnectionStatusChanged: %1: resuming broken filetransfer from position: %2").arg(f.file->fileName()).arg(f.bytesSent); + tox_file_send_control(static_cast(core)->tox, friendId, 1, f.fileNum, TOX_FILECONTROL_RESUME_BROKEN, reinterpret_cast(&f.bytesSent), sizeof(uint64_t)); emit static_cast(core)->fileTransferBrokenUnbroken(f, false); } } @@ -356,7 +355,7 @@ void Core::onFileSendRequestCallback(Tox*, int32_t friendnumber, uint8_t filenum emit static_cast(core)->fileReceiveRequested(fileRecvQueue.last()); } void Core::onFileControlCallback(Tox* tox, int32_t friendnumber, uint8_t receive_send, uint8_t filenumber, - uint8_t control_type, const uint8_t* data, uint16_t, void *core) + uint8_t control_type, const uint8_t* data, uint16_t length, void *core) { ToxFile* file{nullptr}; if (receive_send == 1) @@ -451,8 +450,12 @@ void Core::onFileControlCallback(Tox* tox, int32_t friendnumber, uint8_t receive } else if (receive_send == 1 && control_type == TOX_FILECONTROL_RESUME_BROKEN) { + if (length != sizeof(uint64_t)) + return; + qDebug() << "Core::onFileControlCallback: TOX_FILECONTROL_RESUME_BROKEN"; - uint64_t resumePos = *(const uint64_t*)(data); + + uint64_t resumePos = *reinterpret_cast(data); if (resumePos >= file->filesize) { From 904de559e55c2c726ef89ac4366a4ba15d6b5787 Mon Sep 17 00:00:00 2001 From: apprb Date: Tue, 30 Sep 2014 00:22:19 +0700 Subject: [PATCH 118/205] FileTransferInstance responce on broken filetransfer state --- core.cpp | 8 ++++++++ filetransferinstance.cpp | 19 +++++++++++++++++++ filetransferinstance.h | 1 + widget/form/chatform.cpp | 2 ++ 4 files changed, 30 insertions(+) diff --git a/core.cpp b/core.cpp index f1de8614f..ad0d943a3 100644 --- a/core.cpp +++ b/core.cpp @@ -442,6 +442,11 @@ void Core::onFileControlCallback(Tox* tox, int32_t friendnumber, uint8_t receive } else if (receive_send == 0 && control_type == TOX_FILECONTROL_ACCEPT) { + if (file->status == ToxFile::BROKEN) + { + emit static_cast(core)->fileTransferBrokenUnbroken(*file, false); + file->status = ToxFile::TRANSMITTING; + } emit static_cast(core)->fileTransferRemotePausedUnpaused(*file, false); } else if ((receive_send == 0 || receive_send == 1) && control_type == TOX_FILECONTROL_PAUSE) @@ -464,6 +469,9 @@ void Core::onFileControlCallback(Tox* tox, int32_t friendnumber, uint8_t receive return; } + file->status = ToxFile::TRANSMITTING; + emit static_cast(core)->fileTransferBrokenUnbroken(*file, false); + file->bytesSent = resumePos; tox_file_send_control(tox, file->friendId, 0, file->fileNum, TOX_FILECONTROL_ACCEPT, nullptr, 0); } diff --git a/filetransferinstance.cpp b/filetransferinstance.cpp index 0799c9615..75ab36d3e 100644 --- a/filetransferinstance.cpp +++ b/filetransferinstance.cpp @@ -291,6 +291,12 @@ QString FileTransferInstance::getHtmlImage() rightBtnImg = QImage(":/ui/fileTransferInstance/pauseGreyFileButton.png"); res = draw2ButtonsForm("silver", leftBtnImg, rightBtnImg); + } else if (state == tsBroken) + { + QImage leftBtnImg(":/ui/fileTransferInstance/stopFileButton.png"); + QImage rightBtnImg(":/ui/fileTransferInstance/pauseGreyFileButton.png"); + + res = draw2ButtonsForm("red", leftBtnImg, rightBtnImg); } else if (state == tsCanceled) { res = drawButtonlessForm("red"); @@ -416,3 +422,16 @@ QImage FileTransferInstance::drawProgressBarImg(const double &part, int w, int h return progressBar; } + +void FileTransferInstance::onFileTransferBrokenUnbroken(ToxFile File, bool broken) +{ + if (File.fileNum != fileNum || File.friendId != friendId || File.direction != direction) + return; + + if (broken) + state = tsBroken; + else + state = tsProcessing; + + emit stateUpdated(); +} diff --git a/filetransferinstance.h b/filetransferinstance.h index 23f75f282..c627fb3ee 100644 --- a/filetransferinstance.h +++ b/filetransferinstance.h @@ -43,6 +43,7 @@ public slots: void onFileTransferAccepted(ToxFile File); void onFileTransferPaused(int FriendId, int FileNum, ToxFile::FileDirection Direction); void onFileTransferRemotePausedUnpaused(ToxFile File, bool paused); + void onFileTransferBrokenUnbroken(ToxFile File, bool broken); void pressFromHtml(QString); signals: diff --git a/widget/form/chatform.cpp b/widget/form/chatform.cpp index 9c57f0d88..ed307bc89 100644 --- a/widget/form/chatform.cpp +++ b/widget/form/chatform.cpp @@ -119,6 +119,7 @@ void ChatForm::startFileSend(ToxFile file) connect(Core::getInstance(), SIGNAL(fileTransferAccepted(ToxFile)), fileTrans, SLOT(onFileTransferAccepted(ToxFile))); connect(Core::getInstance(), SIGNAL(fileTransferPaused(int,int,ToxFile::FileDirection)), fileTrans, SLOT(onFileTransferPaused(int,int,ToxFile::FileDirection))); connect(Core::getInstance(), SIGNAL(fileTransferRemotePausedUnpaused(ToxFile,bool)), fileTrans, SLOT(onFileTransferRemotePausedUnpaused(ToxFile,bool))); + connect(Core::getInstance(), SIGNAL(fileTransferBrokenUnbroken(ToxFile, bool)), fileTrans, SLOT(onFileTransferBrokenUnbroken(ToxFile, bool))); QString name = Widget::getInstance()->getUsername(); if (name == previousName) @@ -142,6 +143,7 @@ void ChatForm::onFileRecvRequest(ToxFile file) connect(Core::getInstance(), SIGNAL(fileTransferAccepted(ToxFile)), fileTrans, SLOT(onFileTransferAccepted(ToxFile))); connect(Core::getInstance(), SIGNAL(fileTransferPaused(int,int,ToxFile::FileDirection)), fileTrans, SLOT(onFileTransferPaused(int,int,ToxFile::FileDirection))); connect(Core::getInstance(), SIGNAL(fileTransferRemotePausedUnpaused(ToxFile,bool)), fileTrans, SLOT(onFileTransferRemotePausedUnpaused(ToxFile,bool))); + connect(Core::getInstance(), SIGNAL(fileTransferBrokenUnbroken(ToxFile, bool)), fileTrans, SLOT(onFileTransferBrokenUnbroken(ToxFile, bool))); Widget* w = Widget::getInstance(); if (!w->isFriendWidgetCurActiveWidget(f)|| w->getIsWindowMinimized() || !w->isActiveWindow()) From 67ffbfcb6ef6f3c52103f8fbdabbf35f21fb9d2c Mon Sep 17 00:00:00 2001 From: krepa098 Date: Mon, 29 Sep 2014 10:38:31 +0200 Subject: [PATCH 119/205] fix #334 --- widget/friendwidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/widget/friendwidget.cpp b/widget/friendwidget.cpp index 5bce871f7..ad16ac75c 100644 --- a/widget/friendwidget.cpp +++ b/widget/friendwidget.cpp @@ -210,7 +210,7 @@ void FriendWidget::onAvatarRemoved(int FriendId) return; isDefaultAvatar = true; - avatar->setPixmap(QPixmap(":img/contact.png")); + avatar->setPixmap(QPixmap(":img/contact_dark.png")); } void FriendWidget::mousePressEvent(QMouseEvent *ev) From 767f164a14c97163abfe7b8639e7acae3b691534 Mon Sep 17 00:00:00 2001 From: dubslow Date: Mon, 29 Sep 2014 13:28:59 -0500 Subject: [PATCH 120/205] fix file mvs --- core.cpp | 6 +++--- main.cpp | 2 +- qtox.pro | 20 ++++++++++---------- widget/emoticonswidget.cpp | 4 ++-- widget/form/genericchatform.cpp | 6 +++--- widget/groupwidget.cpp | 2 +- widget/settingsdialog.cpp | 4 ++-- widget/tool/chatactions/messageaction.cpp | 2 +- widget/widget.cpp | 4 ++-- 9 files changed, 25 insertions(+), 25 deletions(-) diff --git a/core.cpp b/core.cpp index 403b3e8b9..2657f716e 100644 --- a/core.cpp +++ b/core.cpp @@ -15,9 +15,9 @@ */ #include "core.h" -#include "cdata.h" -#include "cstring.h" -#include "settings.h" +#include "misc/cdata.h" +#include "misc/cstring.h" +#include "misc/settings.h" #include "widget/widget.h" #include diff --git a/main.cpp b/main.cpp index 1cdac827e..8e981baa5 100644 --- a/main.cpp +++ b/main.cpp @@ -15,7 +15,7 @@ */ #include "widget/widget.h" -#include "settings.h" +#include "misc/settings.h" #include #include #include diff --git a/qtox.pro b/qtox.pro index c5bf81c1b..f7bd7bf3a 100644 --- a/qtox.pro +++ b/qtox.pro @@ -91,17 +91,17 @@ HEADERS += widget/form/addfriendform.h \ friend.h \ group.h \ grouplist.h \ - settings.h \ + misc/settings.h \ core.h \ friendlist.h \ - cdata.h \ - cstring.h \ + misc/cdata.h \ + misc/cstring.h \ widget/selfcamview.h \ widget/camera.h \ widget/netcamview.h \ - smileypack.h \ + misc/smileypack.h \ widget/emoticonswidget.h \ - style.h \ + misc/style.h \ widget/adjustingscrollarea.h \ widget/croppinglabel.h \ widget/friendlistwidget.h \ @@ -135,15 +135,15 @@ SOURCES += \ group.cpp \ grouplist.cpp \ main.cpp \ - settings.cpp \ - cdata.cpp \ - cstring.cpp \ + misc/settings.cpp \ + misc/cdata.cpp \ + misc/cstring.cpp \ widget/selfcamview.cpp \ widget/camera.cpp \ widget/netcamview.cpp \ - smileypack.cpp \ + misc/smileypack.cpp \ widget/emoticonswidget.cpp \ - style.cpp \ + misc/style.cpp \ widget/adjustingscrollarea.cpp \ widget/croppinglabel.cpp \ widget/friendlistwidget.cpp \ diff --git a/widget/emoticonswidget.cpp b/widget/emoticonswidget.cpp index f471e8729..1e3d0ea4e 100644 --- a/widget/emoticonswidget.cpp +++ b/widget/emoticonswidget.cpp @@ -15,8 +15,8 @@ */ #include "emoticonswidget.h" -#include "smileypack.h" -#include "style.h" +#include "misc/smileypack.h" +#include "misc/style.h" #include #include diff --git a/widget/form/genericchatform.cpp b/widget/form/genericchatform.cpp index c992ba563..26bd958ba 100644 --- a/widget/form/genericchatform.cpp +++ b/widget/form/genericchatform.cpp @@ -17,11 +17,11 @@ #include "genericchatform.h" #include "ui_mainwindow.h" #include -#include "smileypack.h" +#include "misc/smileypack.h" #include "widget/emoticonswidget.h" -#include "style.h" +#include "misc/style.h" #include "widget/widget.h" -#include "settings.h" +#include "misc/settings.h" #include "widget/tool/chatactions/messageaction.h" #include "widget/tool/chatactions/systemmessageaction.h" #include "widget/chatareawidget.h" diff --git a/widget/groupwidget.cpp b/widget/groupwidget.cpp index 7bd1683c9..d803063ce 100644 --- a/widget/groupwidget.cpp +++ b/widget/groupwidget.cpp @@ -17,7 +17,7 @@ #include "groupwidget.h" #include "grouplist.h" #include "group.h" -#include "settings.h" +#include "misc/settings.h" #include "widget/form/groupchatform.h" #include "widget/maskablepixmapwidget.h" #include diff --git a/widget/settingsdialog.cpp b/widget/settingsdialog.cpp index d81973286..947395350 100644 --- a/widget/settingsdialog.cpp +++ b/widget/settingsdialog.cpp @@ -1,10 +1,10 @@ #include "settingsdialog.h" -#include "settings.h" +#include "misc/settings.h" #include "widget.h" #include "camera.h" #include "selfcamview.h" #include "core.h" -#include "smileypack.h" +#include "misc/smileypack.h" #include #include diff --git a/widget/tool/chatactions/messageaction.cpp b/widget/tool/chatactions/messageaction.cpp index 84ce86194..9904be470 100644 --- a/widget/tool/chatactions/messageaction.cpp +++ b/widget/tool/chatactions/messageaction.cpp @@ -15,7 +15,7 @@ */ #include "messageaction.h" -#include "smileypack.h" +#include "misc/smileypack.h" MessageAction::MessageAction(const QString &author, const QString &message, const QString &date, const bool &me) : ChatAction(me, author, date), diff --git a/widget/widget.cpp b/widget/widget.cpp index 2b322eecd..a70fac605 100644 --- a/widget/widget.cpp +++ b/widget/widget.cpp @@ -17,7 +17,7 @@ #include "widget.h" #include "ui_mainwindow.h" #include "core.h" -#include "settings.h" +#include "misc/settings.h" #include "friend.h" #include "friendlist.h" #include "widget/tool/friendrequestdialog.h" @@ -26,7 +26,7 @@ #include "group.h" #include "widget/groupwidget.h" #include "widget/form/groupchatform.h" -#include "style.h" +#include "misc/style.h" #include "selfcamview.h" #include "widget/friendlistwidget.h" #include "camera.h" From 12c265aa9ba3cb6096efab2c73e1e20a3e934431 Mon Sep 17 00:00:00 2001 From: Olexandr Nesterenko Date: Mon, 29 Sep 2014 22:05:48 +0300 Subject: [PATCH 121/205] Add Ukrainian translation --- qtox.pro | 3 +- res.qrc | 1 + translations/uk.qm | Bin 0 -> 7608 bytes translations/uk.ts | 485 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 488 insertions(+), 1 deletion(-) create mode 100644 translations/uk.qm create mode 100644 translations/uk.ts diff --git a/qtox.pro b/qtox.pro index f7bd7bf3a..aa45650fd 100644 --- a/qtox.pro +++ b/qtox.pro @@ -35,7 +35,8 @@ TRANSLATIONS = translations/de.ts \ translations/ru.ts \ translations/pl.ts \ translations/fi.ts \ - translations/mannol.ts + translations/mannol.ts \ + translations/uk.ts RESOURCES += res.qrc diff --git a/res.qrc b/res.qrc index d085ca820..c4719df01 100644 --- a/res.qrc +++ b/res.qrc @@ -142,6 +142,7 @@ translations/pl.qm translations/fi.qm translations/mannol.qm + translations/uk.qm img/avatar_mask.png img/group_2x.png diff --git a/translations/uk.qm b/translations/uk.qm new file mode 100644 index 0000000000000000000000000000000000000000..53c004e9b1071fd0a8f894794c4f253219be7de8 GIT binary patch literal 7608 zcmb_hTWlQF89sK-uD!N*?buG@I8HiAb0;KD;!A9=?X1^v>|h)dJB}cNcCtIRhwRR5 zW@qh~hl&a+g;Lt8loB8ks!A`k4?!wIRiOm|ZK9~M?)w@HCRi+s8on&myuNi;r5yo0x zX8gkQxc-&-Mmrg6e27(@o@Z>ek9GW)Ggfnw^}M^EvEXYgl6f3w?_i^gJ$U{wJJR(8 zW6h&%{Harntv$!?`4H#p&#`Adxr+M_uxG#IV=UCj-un7Gc)qrhM_$Fb*DLGqk1@8Y zs?yl@Hu&yYvHJSY8DoE2F}CjC;CFGwl_$T(SjF`f?|kQD#scU0*l)q7wVy9taPfRS zKR@;g>DxL%!}KKY-kqe1r3wflsH;Xg>sbU-EsU_BqCCSNneY=o^eR1$-|( zca<^zy1X`peb+97Uz6=W-TE4E8}!?CI9Ju=w}+48`f^o83!XRpp{i!fleq4w`u3%N zLGF*LuDt&c^uJVH@zsYRSAF$^SF6D9{Xp={TcGnoVAa!qX3YOU;M|32$n%rHo1?#E ztgbR}?fD;q?uo#kg4gkTGVrMbeyu;M`OS-Cpu1G_&+m1>K38iy-^P{STX%Rnf{}`H;&)? zy(jYSe%{BA;#stsNc-{EIBLcXZ2=#)mU4^*(^v$Y%paMV)aQ%}VtfRQ2f(DAcYl6t zr{?X&8?)U2w(ZcRorj^%5b5se+kxK$N`ugh5Pr&VUDKLN7fRpCn<0INlDq?iqR?c9 z?^7gdBk{O4;+TdN7w3ccEq{*KPEvr-D?kVX|2~33pgqGoa6Jst5%IeKW2UiTHo>M8 zo7O{)V>{a7yqPexgl(UOyjmuu4Npvw)FrsK2(Dz~4k!@@?@rjYpC45;tL`+?X;`WZ zfeyX~;*n$Q!?78_I1W*J@td5a7r*H)OiREtCeUVuB{au4 zlQGh688&g=C}5Gg5kSyP0xno|;xjCSK%jVfcL`5Guy|py90%`iNhEep&l_YXVK$g7 zZX0RMvRy4^Tdsbq&`f-GnM+Ey^QO{SOE)&!cD@x@P4g2#jf_X$5fK5`&k0E~W3K7)>G8M&2h8DNoHfgutgfW+{u_GJR^A44bqOKJ)Dd{mjEF%90|V2YaW<&L z3KF%Xp(XXDQ^sH!-x-06B84DyDS1XkI+c1JhOdy@QaT+H5fZ_bq6di=_p)vr!O2|y z*m&GB&Zdl*Ys57xlRRZOnmwzz##t9m9J8IWS>>Kv5~Q0V2EtP8Q~2(?sc`N5kV0f< zN#PL42rdfhJTc3_H4V3=+$$j>%wZ3L2lps1<&tXza?*2Ibs~6cZ}u(mu1dXZqmu87 zciR~)rd!)w@+NJ`&Nyi!F{|nDE-w{qEF)N3$y758A$oY9Vo)oR3TPqi5~1qoyzZ*R zzEzkYj5E^^aS)#0E&!HEO4(acTQzRSbl0>k5&nyg>FTE>-R2Q6n09n4J!?2)R@&9A zn5>|!$ie_ZMAd!(M_?99sV^9$u_tADYQHNm2PF55QC52JgC_VKfgdB=Ly`g98G^2( z%KuST@N74pZt$ed){7aKepDDzX4DZc9H|}2cTP}XyKuf8=P80BR4VZqg*~LZ)<@ERYe+%?7VaxLJ7)Ndozmxh&1?LDoKhrea2A2aSpQoiB&`_LYCqNhfZhhWrOBhTU+<+VOIE)@i7AR=&W zaTlLiC+?HwL)_10HmHX?t?C7Vud(RAl2_1#d` z4b+^0wrpESCIBcnp$E+avif)$6=-bu#>j2wt4cym(^9r8qh_(EpdAcF?bMPd zve*CBNt>N8<8y{9d}*`iOO#>IK@fNXAcA*4d^8G{Iaun)tOW{e)S)@Y&ZJ2HVw#&o zVC0ztvh$ z4rS7{hb&6{+Suemm$sb>eKLvm)rjvPuC<2^%W(9B8lyHLtx^-^wc-$e5I(YOzEPwb zyu(`lR8vH8vk0++fLL_dP=}g%Sj`KtDEQ^VYvrBfaMT{9Y)2KXBBDoBt(t+ovh6!H zAk@r{Dwh*u2v|`wLbgW67r{d8sdF01%b&wjl#0{dghtL!`FYWH!~_&Kft_nROYnlU zYv^&&JmG~*I-@73!=6PNcS?df%9{j)!*JKbN__&B`Z@x;7xHw9rUVj+{3ts)s!Rmk z0r{4KzIG~!^uDA`>ao)$S+*9iq_Rp1qlHjJd}zp%qS+|I_ki%_{17IGkYOxig&HW_ z0a=P43UVTziv?x1v!j6(MjjBUR$e^%FOqSF+(zRZ=of%u! zAng`;f{IIizCrs70ZB+f6jcvEvn_0|BHyrOFDz&{qRAvK#36W?qWrVcUo)Ya>}4Ei zp>eBhn^{GG2L7uE}~J*{pb+4<*gt1gf9KOZY*wCuIVnRe76VYv4}p&JEcZj;eCnK_j(W7?QCi=~V3Y{I^na2?+WEhsY~!6|q1 zPr16A5wTF>$jv6t;v>z#3;7OCU1~E@i*D7)8>x%W-}2tcYXL~tnme&dIAL0Gdr{QV zO^9LYxGAkmyOl2)%?K)M&JgpHO0}hkhD3qxg$)Ez1)wjQKr>zH#7+S?6-)0-p7Y4j zn3DeT}4Cm+qux6F{Mgbu7wU=CB02joqbW@kd=Jaob&`grRL@c9NoHCT%4= zpN75miD#HqaGx6SY^z2iDyDth$+qVC0knPwYfluKWGZ3M3{Nwd%&?f`gi95QO>HMt zL%ADS9uooK85Osxd?W>wHqeq#B5Yg5{dUt0oo4wYmiA(ykXh*`-BpCwGC jR9l;4ieeI%OogWTT+adV;L3_mcGP~_T**J#Rnzo8t!#&A literal 0 HcmV?d00001 diff --git a/translations/uk.ts b/translations/uk.ts new file mode 100644 index 000000000..70d143cdc --- /dev/null +++ b/translations/uk.ts @@ -0,0 +1,485 @@ + + + + + AVPage + + + Video Settings + Параметри відео + + + + + Show video preview + On a button + Показати вікно попереднього перегляду + + + + Hide video preview + On a button + Приховати вікно попереднього перегляду + + + + AddFriendForm + + + Add Friends + Додати друзів + + + + Tox ID + Tox ID of the person you're sending a friend request to + Tox ID + + + + Message + The message you send in friend requests + Повідомлення + + + + Send friend request + Надіслати запит на дружбу + + + + Tox me maybe? + Default message in friend requests if the field is left blank. Write something appropriate! + Може поспілкуємось? + + + + Please fill in a valid Tox ID + Tox ID of the friend you're sending a friend request to + Заповніть коректним Tox ID + + + + You can't add yourself as a friend! + When trying to add your own Tox ID as friend + Ви не можете додати самого себе до друзів! + + + + This address does not exist + The DNS gives the Tox ID associated to toxme.se addresses + Цієї адреси не існує + + + + Error while looking up DNS + The DNS gives the Tox ID associated to toxme.se addresses + Помилка під час перегляду DNS + + + + Unexpected number of text records + Error with the DNS + Неочікуване число текстових записів + + + + Unexpected number of values in text record + Error with the DNS + Неочікуване число значень в текстових записах + + + + The DNS lookup does not contain any Tox ID + Error with the DNS + Відповідь DNS не містить жодного Tox ID + + + + + The DNS lookup does not contain a valid Tox ID + Error with the DNS + Відповідь DNS не містить жодного коректного Tox ID + + + + ChatForm + + + Send a file + Надіслати файл + + + + FileTransferInstance + + + Save a file + Title of the file saving dialog + Зберегти файл + + + + Location not writable + Title of permissions popup + Немає прав на запис + + + + You do not have permission to write that location. Choose another, or cancel the save dialog. + text of permissions popup + Ви не маєте прав на запис за цим розташуванням. Оберіть інше місце призначення, або скасуйте передачу. + + + + FilesForm + + + Transfered Files + "Headline" of the window + Передані файли + + + + Downloads + Завантажені + + + + Uploads + Вивантажені + + + + FriendRequestDialog + + + Friend request + Title of the window to aceept/deny a friend request + Запит на дружбу + + + + Someone wants to make friends with you + Дехто хоче долучитися до переліку друзів з вами + + + + User ID: + ID користувача: + + + + Friend request message: + Повідомлення запиту: + + + + Accept + Accept a friend request + Прийняти + + + + Reject + Reject a friend request + Відхилити + + + + FriendWidget + + + Copy friend ID + Menu to copy the Tox ID of that friend + Копіювати дружній ID + + + + Invite in group + Menu to invite a friend in a groupchat + Запросити до групи + + + + Remove friend + Menu to remove the friend from our friendlist + Вилучити з друзів + + + + GeneralPage + + + General Settings + Основні параметри + + + + Enable IPv6 (recommended) + Text on a checkbox to enable IPv6 + Дозволити IPv6 (рекомендовано) + + + + Use translations + Text on a checkbox to enable translations + Використовувати мову системи + + + + Make Tox portable + Text on a checkbox to make qTox a portable application + Портативний запуск + + + + Save settings to the working directory instead of the usual conf dir + describes makeToxPortable checkbox + Зберігати налаштування в робочий теці + + + + Theme + Графічна тема + + + + Smiley Pack + Графічний пакунок емоційних картинок + + + + GenericChatForm + + + + Save chat log + Зберегти чат + + + + GroupChatForm + + + %1 users in chat + Number of users in chat + Користувачів у чаті: %1 + + + + <Unknown> + <Невідомо> + + + + %1 users in chat + Користувачів у чаті: %1 + + + + GroupWidget + + + + %1 users in chat + Користувачів у чаті: %1 + + + + + 0 users in chat + Немає користувачів + + + + Quit group + Menu to quit a groupchat + Вийти з групи + + + + IdentityPage + + + Public Information + Публічна інформація + + + + Name + Username/nick + Ім'я + + + + Status + Status message + Статус + + + + Tox ID + Tox ID + + + + Your Tox ID + Ваш Tox ID + + + + MainWindow + + + qTox + qTox + + + + Your name + Ваше ім'я + + + + Your status + Ваш статус + + + + Add friends + Додати друзів + + + + Create a group chat + Створити груповий чат + + + + View completed file transfers + Переглянути завершені передачі файлів + + + + Change your settings + Змінити параметри + + + + Close + Закрити + + + + Ctrl+Q + Ctrl+Q + + + + SelfCamView + + + Tox video test + Title of the window to test the video/webcam + Перевірка відео tox + + + + SettingsDialog + + + qTox – Settings + qTox - Параметри + + + + General + Основні + + + + Identity + Ідентифікація + + + + Privacy + Приватність + + + + Audio/Video + Аудіо/Відео + + + + Ok + Гаразд + + + + Cancel + Скасувати + + + + Apply + Застосувати + + + + Widget + + + Online + Button to set your status to 'Online' + В мережі + + + + Away + Button to set your status to 'Away' + Відійшов + + + + Busy + Button to set your status to 'Busy' + Зайнятий + + + + Choose a profile picture + Оберіть зображення для профілю + + + + + + Error + Помилка + + + + Unable to open this file + Неможливо відкрити цей файл + + + + Unable to read this image + Неможливо прочитати це зображення + + + + This image is too big + Зображення завелике + + + + <Unknown> + Placeholder when we don't know someone's name in a group chat + <Невідомо> + + + From 39abf83b2e890c490f54b5a2cbee32c5bdf10a05 Mon Sep 17 00:00:00 2001 From: dubslow Date: Mon, 29 Sep 2014 16:36:23 -0500 Subject: [PATCH 122/205] remove avatar debug prints --- core.cpp | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/core.cpp b/core.cpp index 154087d60..94f76c318 100644 --- a/core.cpp +++ b/core.cpp @@ -563,20 +563,13 @@ void Core::onAvatarInfoCallback(Tox*, int32_t friendnumber, uint8_t format, Core* core = static_cast(_core); if (format == TOX_AVATAR_FORMAT_NONE) - { - qDebug() << "Core: Got null avatar info from" << friendnumber; emit core->friendAvatarRemoved(friendnumber); - } else { QByteArray oldHash = Settings::getInstance().getAvatarHash(core->getFriendAddress(friendnumber)); - if (QByteArray((char*)hash, TOX_HASH_LENGTH) != oldHash) // comparison failed miserably if I didn't convert hash to QByteArray - { - qDebug() << "Core: got different avatar hash from" << friendnumber; + if (QByteArray((char*)hash, TOX_HASH_LENGTH) != oldHash) + // comparison failed miserably if I didn't convert hash to QByteArray tox_request_avatar_data(core->tox, friendnumber); - } - else - qDebug() << "Core: Got old avatar info from" << friendnumber; } } @@ -585,11 +578,8 @@ void Core::onAvatarDataCallback(Tox*, int32_t friendnumber, uint8_t, { QPixmap pic; pic.loadFromData((uchar*)data, datalen); - if (pic.isNull()) - qDebug() << "Core: Got null avatar from "<(core)->getFriendAddress(friendnumber)); Settings::getInstance().saveAvatarHash(QByteArray((char*)hash, TOX_HASH_LENGTH), static_cast(core)->getFriendAddress(friendnumber)); emit static_cast(core)->friendAvatarChanged(friendnumber, pic); From d1919658e1a6f4eb5245862763e23810fe6374a7 Mon Sep 17 00:00:00 2001 From: dubslow Date: Mon, 29 Sep 2014 21:24:31 -0500 Subject: [PATCH 123/205] tweak #340 dht connecting, remove dropped avatars from cache --- core.cpp | 43 +++++++++++++++++++++++++++++++++++++------ core.h | 1 + 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/core.cpp b/core.cpp index 94f76c318..4744fda90 100644 --- a/core.cpp +++ b/core.cpp @@ -220,12 +220,21 @@ void Core::start() process(); // starts its own timer } +/* Using the now commented out statements in checkConnection(), I watched how + * many ticks disconnects-after-initial-connect lasted. Out of roughly 15 trials, + * 5 disconnected; 4 were DCd for less than 20 ticks, while the 5th was ~50 ticks. + * So I set the tolerance here at 25, and initial DCs should be very rare now. + * This should be able to go to 50 or 100 without affecting legitimate disconnects' + * downtime, but lets be conservative for now. + */ +#define CORE_DISCONNECT_TOLERANCE 25 + void Core::process() { if (!tox) return; - static int retries = 0; + static int tolerance = CORE_DISCONNECT_TOLERANCE; tox_do(tox); #ifdef DEBUG @@ -234,10 +243,10 @@ void Core::process() #endif if (checkConnection()) - retries = 0; - else if (retries < 2) + tolerance = CORE_DISCONNECT_TOLERANCE; + else if (--tolerance) { - retries++; + tolerance = CORE_DISCONNECT_TOLERANCE; bootstrapDht(); } @@ -247,17 +256,21 @@ void Core::process() bool Core::checkConnection() { static bool isConnected = false; + //static int count = 0; bool toxConnected = tox_isconnected(tox); if (toxConnected && !isConnected) { qDebug() << "Core: Connected to DHT"; emit connected(); isConnected = true; + //if (count) qDebug() << "Core: disconnect count:" << count; + //count = 0; } else if (!toxConnected && isConnected) { qDebug() << "Core: Disconnected to DHT"; emit disconnected(); isConnected = false; - } + //count++; + } //else if (!toxConnected) count++; return isConnected; } @@ -272,7 +285,7 @@ void Core::bootstrapDht() qDebug() << "Core: Bootstraping to the DHT ..."; int i=0; - while (i < 2) + while (i < 3) { const Settings::DhtServer& dhtServer = dhtServerList[j % listSize]; if (tox_bootstrap_from_address(tox, dhtServer.address.toLatin1().data(), @@ -563,13 +576,23 @@ void Core::onAvatarInfoCallback(Tox*, int32_t friendnumber, uint8_t format, Core* core = static_cast(_core); if (format == TOX_AVATAR_FORMAT_NONE) + { + qDebug() << "Core: Got null avatar info from" << core->getFriendUsername(friendnumber); emit core->friendAvatarRemoved(friendnumber); + QFile::remove(QDir(Settings::getInstance().getSettingsDirPath()).filePath("avatars/"+core->getFriendAddress(friendnumber).left(64)+".png")); + QFile::remove(QDir(Settings::getInstance().getSettingsDirPath()).filePath("avatars/"+core->getFriendAddress(friendnumber).left(64)+".hash")); + } else { QByteArray oldHash = Settings::getInstance().getAvatarHash(core->getFriendAddress(friendnumber)); if (QByteArray((char*)hash, TOX_HASH_LENGTH) != oldHash) // comparison failed miserably if I didn't convert hash to QByteArray + { + qDebug() << "Core: Got new avatar info from" << core->getFriendUsername(friendnumber); tox_request_avatar_data(core->tox, friendnumber); + } + else + qDebug() << "Core: Got same avatar info from" << core->getFriendUsername(friendnumber); } } @@ -580,6 +603,7 @@ void Core::onAvatarDataCallback(Tox*, int32_t friendnumber, uint8_t, pic.loadFromData((uchar*)data, datalen); if (!pic.isNull()) { + qDebug() << "Core: Got avatar data from" << static_cast(core)->getFriendUsername(friendnumber); Settings::getInstance().saveAvatar(pic, static_cast(core)->getFriendAddress(friendnumber)); Settings::getInstance().saveAvatarHash(QByteArray((char*)hash, TOX_HASH_LENGTH), static_cast(core)->getFriendAddress(friendnumber)); emit static_cast(core)->friendAvatarChanged(friendnumber, pic); @@ -1283,6 +1307,13 @@ QString Core::getFriendAddress(int friendNumber) const return id; } +QString Core::getFriendUsername(int friendnumber) const +{ + uint8_t name[TOX_MAX_NAME_LENGTH]; + tox_get_name(tox, friendnumber, name); + return CString::toString(name, tox_get_name_size(tox, friendnumber)); +} + QList Core::splitMessage(const QString &message) { QList splittedMsgs; diff --git a/core.h b/core.h index 4b5aa7a86..2419bb6c3 100644 --- a/core.h +++ b/core.h @@ -42,6 +42,7 @@ public: QString getGroupPeerName(int groupId, int peerId) const; QList getGroupPeerNames(int groupId) const; QString getFriendAddress(int friendNumber) const; + QString getFriendUsername(int friendNumber) const; int joinGroupchat(int32_t friendnumber, const uint8_t* friend_group_public_key,uint16_t length) const; void quitGroupChat(int groupId) const; void dispatchVideoFrame(vpx_image img) const; From 4719ea28a8ce04278981473a9d3d775a4a464a58 Mon Sep 17 00:00:00 2001 From: dubslow Date: Mon, 29 Sep 2014 21:29:39 -0500 Subject: [PATCH 124/205] oops, don't reset tolerance upon bootstrap --- core.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/core.cpp b/core.cpp index 4744fda90..d73b17683 100644 --- a/core.cpp +++ b/core.cpp @@ -244,9 +244,8 @@ void Core::process() if (checkConnection()) tolerance = CORE_DISCONNECT_TOLERANCE; - else if (--tolerance) + else if (!(--tolerance)) { - tolerance = CORE_DISCONNECT_TOLERANCE; bootstrapDht(); } @@ -285,7 +284,7 @@ void Core::bootstrapDht() qDebug() << "Core: Bootstraping to the DHT ..."; int i=0; - while (i < 3) + while (i < 4) { const Settings::DhtServer& dhtServer = dhtServerList[j % listSize]; if (tox_bootstrap_from_address(tox, dhtServer.address.toLatin1().data(), From da8f83943dd81106ab72e25f731acf44cba29016 Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Sun, 28 Sep 2014 10:56:02 +0200 Subject: [PATCH 125/205] Compat with toxcore --- core.cpp | 8 ++++---- core.h | 6 +++--- widget/widget.cpp | 4 ++-- widget/widget.h | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/core.cpp b/core.cpp index 81d022588..da1d24b70 100644 --- a/core.cpp +++ b/core.cpp @@ -279,10 +279,10 @@ void Core::onAction(Tox*/* tox*/, int friendId, const uint8_t *cMessage, uint16_ emit static_cast(core)->actionReceived(friendId, CString::toString(cMessage, cMessageSize)); } -void Core::onGroupInvite(Tox*, int friendnumber, const uint8_t *group_public_key, void *core) +void Core::onGroupInvite(Tox*, int friendnumber, const uint8_t *group_public_key, uint16_t length,void *core) { qDebug() << QString("Core: Group invite by %1").arg(friendnumber); - emit static_cast(core)->groupInviteReceived(friendnumber, group_public_key); + emit static_cast(core)->groupInviteReceived(friendnumber, group_public_key,length); } void Core::onGroupMessage(Tox*, int groupnumber, int friendgroupnumber, const uint8_t * message, uint16_t length, void *core) @@ -1005,10 +1005,10 @@ QList Core::getGroupPeerNames(int groupId) const return names; } -int Core::joinGroupchat(int32_t friendnumber, const uint8_t* friend_group_public_key) const +int Core::joinGroupchat(int32_t friendnumber, const uint8_t* friend_group_public_key,uint16_t length) const { qDebug() << QString("Trying to join groupchat invite by friend %1").arg(friendnumber); - return tox_join_groupchat(tox, friendnumber, friend_group_public_key); + return tox_join_groupchat(tox, friendnumber, friend_group_public_key,length); } void Core::quitGroupChat(int groupId) const diff --git a/core.h b/core.h index 13d051017..129b0cf8f 100644 --- a/core.h +++ b/core.h @@ -41,7 +41,7 @@ public: QString getGroupPeerName(int groupId, int peerId) const; QList getGroupPeerNames(int groupId) const; QString getFriendAddress(int friendNumber) const; - int joinGroupchat(int32_t friendnumber, const uint8_t* friend_group_public_key) const; + int joinGroupchat(int32_t friendnumber, const uint8_t* friend_group_public_key,uint16_t length) const; void quitGroupChat(int groupId) const; void dispatchVideoFrame(vpx_image img) const; @@ -115,7 +115,7 @@ signals: void friendLastSeenChanged(int friendId, const QDateTime& dateTime); void emptyGroupCreated(int groupnumber); - void groupInviteReceived(int friendnumber, const uint8_t *group_public_key); + void groupInviteReceived(int friendnumber, const uint8_t *group_public_key,uint16_t length); void groupMessageReceived(int groupnumber, int friendgroupnumber, const QString& message); void groupNamelistChanged(int groupnumber, int peernumber, uint8_t change); @@ -170,7 +170,7 @@ private: static void onUserStatusChanged(Tox* tox, int friendId, uint8_t userstatus, void* core); static void onConnectionStatusChanged(Tox* tox, int friendId, uint8_t status, void* core); static void onAction(Tox* tox, int friendId, const uint8_t* cMessage, uint16_t cMessageSize, void* core); - static void onGroupInvite(Tox *tox, int friendnumber, const uint8_t *group_public_key, void *userdata); + static void onGroupInvite(Tox *tox, int friendnumber, const uint8_t *group_public_key, uint16_t length,void *userdata); static void onGroupMessage(Tox *tox, int groupnumber, int friendgroupnumber, const uint8_t * message, uint16_t length, void *userdata); static void onGroupNamelistChange(Tox *tox, int groupnumber, int peernumber, uint8_t change, void *userdata); static void onFileSendRequestCallback(Tox *tox, int32_t friendnumber, uint8_t filenumber, uint64_t filesize, diff --git a/widget/widget.cpp b/widget/widget.cpp index 62e362f00..a0d5049b3 100644 --- a/widget/widget.cpp +++ b/widget/widget.cpp @@ -558,9 +558,9 @@ void Widget::copyFriendIdToClipboard(int friendId) } } -void Widget::onGroupInviteReceived(int32_t friendId, const uint8_t* publicKey) +void Widget::onGroupInviteReceived(int32_t friendId, const uint8_t* publicKey,uint16_t length) { - int groupId = core->joinGroupchat(friendId, publicKey); + int groupId = core->joinGroupchat(friendId, publicKey,length); if (groupId == -1) { qWarning() << "Widget::onGroupInviteReceived: Unable to accept invitation"; diff --git a/widget/widget.h b/widget/widget.h index 9512f00e9..e94435fbb 100644 --- a/widget/widget.h +++ b/widget/widget.h @@ -95,7 +95,7 @@ private slots: void onFriendMessageReceived(int friendId, const QString& message); void onFriendRequestReceived(const QString& userId, const QString& message); void onEmptyGroupCreated(int groupId); - void onGroupInviteReceived(int32_t friendId, const uint8_t *publicKey); + void onGroupInviteReceived(int32_t friendId, const uint8_t *publicKey,uint16_t length); void onGroupMessageReceived(int groupnumber, int friendgroupnumber, const QString& message); void onGroupNamelistChanged(int groupnumber, int peernumber, uint8_t change); void removeFriend(int friendId); From 8212a3dad0bd28008d46b4df0aa7326218dc67d0 Mon Sep 17 00:00:00 2001 From: dubslow Date: Tue, 30 Sep 2014 04:44:27 -0500 Subject: [PATCH 126/205] Added all current settings except cam test, which segfaults on init... --- widget/form/settings/avform.cpp | 39 +++++++++++++- widget/form/settings/avform.h | 16 +++++- widget/form/settings/generalform.cpp | 66 ++++++++++++++++------- widget/form/settings/generalform.h | 18 ++++--- widget/form/settings/genericsettings.h | 17 +++--- widget/form/settings/identityform.cpp | 75 ++++++++++++++++++++++++-- widget/form/settings/identityform.h | 33 +++++++++++- widget/form/settings/privacyform.cpp | 1 - widget/form/settingswidget.cpp | 5 +- widget/form/settingswidget.h | 16 +++--- widget/widget.cpp | 12 +++-- widget/widget.h | 3 +- 12 files changed, 243 insertions(+), 58 deletions(-) diff --git a/widget/form/settings/avform.cpp b/widget/form/settings/avform.cpp index e0b0773f9..3a4c86f0a 100644 --- a/widget/form/settings/avform.cpp +++ b/widget/form/settings/avform.cpp @@ -15,14 +15,49 @@ */ #include "avform.h" +#include "widget/camera.h" -AVForm::AVForm() +AVForm::AVForm(Camera* cam) { - prep(); icon.setPixmap(QPixmap(":/img/settings/av.png").scaledToHeight(headLayout.sizeHint().height(), Qt::SmoothTransformation)); label.setText(tr("Audio/Video settings")); + + QGroupBox *group = new QGroupBox(tr("Video Settings")); + + camView = new SelfCamView(cam); + camView->hide(); // hide by default + testVideo = new QPushButton(tr("Show video preview","On a button")); + connect(testVideo, &QPushButton::clicked, this, &AVForm::onTestVideoPressed); + + videoLayout = new QVBoxLayout(); + videoLayout->addWidget(testVideo); + videoLayout->addWidget(camView); + //videoGroup->setLayout(videoLayout); // strangely enough, this causes a segfault.... + + layout.addWidget(group); + layout.addStretch(1); } AVForm::~AVForm() { } + +void AVForm::showTestVideo() +{ + testVideo->setText(tr("Hide video preview","On a button")); + camView->show(); +} + +void AVForm::closeTestVideo() +{ + testVideo->setText(tr("Show video preview","On a button")); + camView->close(); +} + +void AVForm::onTestVideoPressed() +{ + if (camView->isVisible()) + closeTestVideo(); + else + showTestVideo(); +} diff --git a/widget/form/settings/avform.h b/widget/form/settings/avform.h index e214e133e..be7c97dae 100644 --- a/widget/form/settings/avform.h +++ b/widget/form/settings/avform.h @@ -18,16 +18,30 @@ #define AVFORM_H #include "genericsettings.h" +#include "widget/selfcamview.h" +#include +#include +#include +class Camera; class AVForm : public GenericForm { Q_OBJECT public: - AVForm(); + AVForm(Camera* cam); ~AVForm(); +private slots: + void onTestVideoPressed(); private: + QGroupBox* videoGroup; + QVBoxLayout* videoLayout; + QPushButton* testVideo; + SelfCamView* camView; + void showTestVideo(); + void closeTestVideo(); + }; #endif diff --git a/widget/form/settings/generalform.cpp b/widget/form/settings/generalform.cpp index 7a6734383..1c7ed8bff 100644 --- a/widget/form/settings/generalform.cpp +++ b/widget/form/settings/generalform.cpp @@ -16,33 +16,63 @@ #include "generalform.h" #include "widget/form/settingswidget.h" +#include "widget/widget.h" +#include "misc/settings.h" +#include "misc/smileypack.h" GeneralForm::GeneralForm() { - prep(); icon.setPixmap(QPixmap(":/img/settings/general.png").scaledToHeight(headLayout.sizeHint().height(), Qt::SmoothTransformation)); - label.setText(tr("General settings")); - group = new QGroupBox(tr("General Settings")); - enableIPv6 = new QCheckBox(); - enableIPv6->setText(tr("Enable IPv6 (recommended)","Text on a checkbox to enable IPv6")); - useTranslations = new QCheckBox(); - useTranslations->setText(tr("Use translations","Text on a checkbox to enable translations")); - makeToxPortable = new QCheckBox(); - makeToxPortable->setText(tr("Make Tox portable","Text on a checkbox to make qTox a portable application")); - makeToxPortable->setToolTip(tr("Save settings to the working directory instead of the usual conf dir","describes makeToxPortable checkbox")); - - QVBoxLayout *vLayout = new QVBoxLayout(); - vLayout->addWidget(enableIPv6); - vLayout->addWidget(useTranslations); - vLayout->addWidget(makeToxPortable); - group->setLayout(vLayout); - label.setText(tr("General Settings")); + enableIPv6.setText(tr("Enable IPv6 (recommended)","Text on a checkbox to enable IPv6")); + enableIPv6.setChecked(Settings::getInstance().getEnableIPv6()); + useTranslations.setText(tr("Use translations","Text on a checkbox to enable translations")); + useTranslations.setChecked(Settings::getInstance().getUseTranslations()); + makeToxPortable.setText(tr("Make Tox portable","Text on a checkbox to make qTox a portable application")); + makeToxPortable.setChecked(Settings::getInstance().getMakeToxPortable()); + makeToxPortable.setToolTip(tr("Save settings to the working directory instead of the usual conf dir","describes makeToxPortable checkbox")); + + smileyPackLabel.setText(tr("Smiley Pack", "Text on smiley pack label")); + for (auto entry : SmileyPack::listSmileyPacks()) + smileyPackBrowser.addItem(entry.first, entry.second); + smileyPackBrowser.setCurrentIndex(smileyPackBrowser.findData(Settings::getInstance().getSmileyPack())); + headLayout.addWidget(&label); - layout.addWidget(group); + layout.addWidget(&enableIPv6); + layout.addWidget(&useTranslations); + layout.addWidget(&makeToxPortable); + layout.addWidget(&smileyPackLabel); + layout.addWidget(&smileyPackBrowser); + layout.addStretch(); + + connect(&enableIPv6, SIGNAL(stateChanged(int)), this, SLOT(onEnableIPv6Updated())); + connect(&useTranslations, SIGNAL(stateChanged(int)), this, SLOT(onUseTranslationUpdated())); + connect(&makeToxPortable, SIGNAL(stateChanged(int)), this, SLOT(onMakeToxPortableUpdated())); + connect(&smileyPackBrowser, SIGNAL(currentIndexChanged(int)), this, SLOT(onSmileyBrowserIndexChanged(int))); } GeneralForm::~GeneralForm() { } + +void GeneralForm::onEnableIPv6Updated() +{ + Settings::getInstance().setEnableIPv6(enableIPv6.isChecked()); +} + +void GeneralForm::onUseTranslationUpdated() +{ + Settings::getInstance().setUseTranslations(useTranslations.isChecked()); +} + +void GeneralForm::onMakeToxPortableUpdated() +{ + Settings::getInstance().setMakeToxPortable(makeToxPortable.isChecked()); +} + +void GeneralForm::onSmileyBrowserIndexChanged(int index) +{ + QString filename = smileyPackBrowser.itemData(index).toString(); + Settings::getInstance().setSmileyPack(filename); +} diff --git a/widget/form/settings/generalform.h b/widget/form/settings/generalform.h index c484a436d..b33b7ffcb 100644 --- a/widget/form/settings/generalform.h +++ b/widget/form/settings/generalform.h @@ -18,10 +18,8 @@ #define GENERALFORM_H #include "genericsettings.h" -#include +#include #include -#include - class GeneralForm : public GenericForm { @@ -30,12 +28,16 @@ public: GeneralForm(); ~GeneralForm(); +private slots: + void onEnableIPv6Updated(); + void onUseTranslationUpdated(); + void onMakeToxPortableUpdated(); + void onSmileyBrowserIndexChanged(int index); + private: - QGroupBox *group; - QCheckBox* enableIPv6; - QCheckBox* useTranslations; - QCheckBox* makeToxPortable; - QLabel label; + QCheckBox enableIPv6, useTranslations, makeToxPortable; + QLabel label, smileyPackLabel; + QComboBox smileyPackBrowser; }; #endif diff --git a/widget/form/settings/genericsettings.h b/widget/form/settings/genericsettings.h index 760d39cb0..8d6d4e9bb 100644 --- a/widget/form/settings/genericsettings.h +++ b/widget/form/settings/genericsettings.h @@ -26,6 +26,15 @@ class GenericForm : public QObject { Q_OBJECT public: + GenericForm() + { + head.setLayout(&headLayout); + headLayout.addWidget(&icon); + headLayout.addWidget(&label); + body.setLayout(&layout); + } + ~GenericForm() {}; + virtual void show(SettingsWidget& sw) { sw.body->layout()->addWidget(&body); @@ -39,14 +48,6 @@ protected: QHBoxLayout headLayout; QLabel label, icon; QWidget head, body; - void prep() // call in subclass constructor - { - head.setLayout(&headLayout); - headLayout.addWidget(&icon); - headLayout.addWidget(&label); - body.setLayout(&layout); - } - }; #endif diff --git a/widget/form/settings/identityform.cpp b/widget/form/settings/identityform.cpp index 696b2141a..57a69a759 100644 --- a/widget/form/settings/identityform.cpp +++ b/widget/form/settings/identityform.cpp @@ -16,25 +16,90 @@ #include "identityform.h" #include "widget/form/settingswidget.h" +#include "widget/croppinglabel.h" +#include "core.h" #include #include +#include +#include IdentityForm::IdentityForm() { - prep(); icon.setPixmap(QPixmap(":/img/settings/identity.png").scaledToHeight(headLayout.sizeHint().height(), Qt::SmoothTransformation)); label.setText(tr("Your identity")); + + // public + publicGroup = new QGroupBox(tr("Public Information")); + userNameLabel = new QLabel(tr("Name","Username/nick")); + userName = new QLineEdit(); + + statusMessageLabel = new QLabel(tr("Status","Status message")); + statusMessage = new QLineEdit(); + + vLayout = new QVBoxLayout(); + vLayout->addWidget(userNameLabel); + vLayout->addWidget(userName); + vLayout->addWidget(statusMessageLabel); + vLayout->addWidget(statusMessage); + publicGroup->setLayout(vLayout); + + // tox toxGroup = new QGroupBox(tr("Tox ID")); - QLabel* toxIdLabel = new QLabel(tr("Your Tox ID")); - QLineEdit* toxID = new QLineEdit(); - toxID->setReadOnly(true); + toxIdLabel = new CroppingLabel(); + toxIdLabel->setText(tr("Your Tox ID (click to copy)")); + toxId = new ClickableTE(); + QFont small; + small.setPixelSize(13); + small.setKerning(false); + toxId->setTextInteractionFlags(Qt::TextSelectableByMouse); + toxId->setReadOnly(true); + toxId->setFrameStyle(QFrame::NoFrame); + toxId->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + toxId->setFixedHeight(toxId->document()->size().height()*2); + toxId->setFont(small); + QVBoxLayout* toxLayout = new QVBoxLayout(); toxLayout->addWidget(toxIdLabel); - toxLayout->addWidget(toxID); + toxLayout->addWidget(toxId); toxGroup->setLayout(toxLayout); + + layout.setSpacing(30); + layout.addWidget(publicGroup); layout.addWidget(toxGroup); + layout.addStretch(1); + + connect(toxIdLabel, SIGNAL(clicked()), this, SLOT(copyIdClicked())); + connect(toxId, SIGNAL(clicked()), this, SLOT(copyIdClicked())); + connect(userName, SIGNAL(editingFinished()), this, SLOT(onUserNameEdited())); + connect(statusMessage, SIGNAL(editingFinished()), this, SLOT(onStatusMessageEdited())); } IdentityForm::~IdentityForm() { } + +void IdentityForm::copyIdClicked() +{ + toxId->selectAll(); + QString txt = toxId->toPlainText(); + txt.replace('\n',""); + QApplication::clipboard()->setText(txt); +} + +void IdentityForm::onUserNameEdited() +{ + emit userNameChanged(userName->text()); +} + +void IdentityForm::onStatusMessageEdited() +{ + emit statusMessageChanged(statusMessage->text()); +} + +void IdentityForm::show(SettingsWidget& sw) +{ + userName->setText(Core::getInstance()->getUsername()); + statusMessage->setText(Core::getInstance()->getStatusMessage()); + toxId->setText(Core::getInstance()->getSelfId().toString()); + GenericForm::show(sw); +} diff --git a/widget/form/settings/identityform.h b/widget/form/settings/identityform.h index dc616d75e..8e80e0aaf 100644 --- a/widget/form/settings/identityform.h +++ b/widget/form/settings/identityform.h @@ -19,6 +19,20 @@ #include "genericsettings.h" #include +#include +#include +class CroppingLabel; + +class ClickableTE : public QTextEdit +{ + Q_OBJECT +public: + +signals: + void clicked(); +protected: + void mouseReleaseEvent(QMouseEvent*) {emit clicked();} +}; class IdentityForm : public GenericForm { @@ -27,8 +41,25 @@ public: IdentityForm(); ~IdentityForm(); + QLineEdit* userName, * statusMessage; + + void show(SettingsWidget& sw); + +signals: + void userNameChanged(QString); + void statusMessageChanged(QString); + +private slots: + void copyIdClicked(); + void onUserNameEdited(); + void onStatusMessageEdited(); + private: - QGroupBox* toxGroup; + QGroupBox* toxGroup, * publicGroup; + ClickableTE* toxId; + QLabel* userNameLabel, * statusMessageLabel; + CroppingLabel* toxIdLabel; + QVBoxLayout* vLayout, * toxLayout; }; #endif diff --git a/widget/form/settings/privacyform.cpp b/widget/form/settings/privacyform.cpp index e1f737975..683bdff4b 100644 --- a/widget/form/settings/privacyform.cpp +++ b/widget/form/settings/privacyform.cpp @@ -19,7 +19,6 @@ PrivacyForm::PrivacyForm() { - prep(); icon.setPixmap(QPixmap(":/img/settings/privacy.png").scaledToHeight(headLayout.sizeHint().height(), Qt::SmoothTransformation)); label.setText(tr("Privacy settings")); } diff --git a/widget/form/settingswidget.cpp b/widget/form/settingswidget.cpp index 9b5dc7856..dddce56e0 100644 --- a/widget/form/settingswidget.cpp +++ b/widget/form/settingswidget.cpp @@ -17,18 +17,19 @@ #include "settingswidget.h" #include "widget/widget.h" #include "ui_mainwindow.h" +#include "widget/camera.h" #include "widget/form/settings/generalform.h" #include "widget/form/settings/identityform.h" #include "widget/form/settings/privacyform.h" #include "widget/form/settings/avform.h" -SettingsWidget::SettingsWidget() +SettingsWidget::SettingsWidget(Camera* cam) : QWidget() { generalForm = new GeneralForm(); identityForm = new IdentityForm(); privacyForm = new PrivacyForm(); - avForm = new AVForm(); + avForm = new AVForm(cam); main = new QWidget(); body = new QWidget(); diff --git a/widget/form/settingswidget.h b/widget/form/settingswidget.h index 6ee45f90d..b24f7ffb6 100644 --- a/widget/form/settingswidget.h +++ b/widget/form/settingswidget.h @@ -19,6 +19,7 @@ #include #include +class Camera; class GenericForm; class GeneralForm; class IdentityForm; @@ -30,12 +31,17 @@ class SettingsWidget : public QWidget { Q_OBJECT public: - SettingsWidget(); + SettingsWidget(Camera* cam); ~SettingsWidget(); void show(Ui::MainWindow &ui); QWidget *head, *body; // keep the others private + GenericForm* active; + GeneralForm* generalForm; + IdentityForm* identityForm; + PrivacyForm* privacyForm; + AVForm* avForm; public slots: //void setFriendAddress(const QString& friendAddress); @@ -51,14 +57,8 @@ private: // main consists of body+foot for Ui::MainWindow QVBoxLayout *mainLayout; - GenericForm* active; - GeneralForm* generalForm; - IdentityForm* identityForm; - PrivacyForm* privacyForm; - AVForm* avForm; void hideSettingsForms(); - - + // the code pertaining to the icons is mostly copied from ui_mainwindow.h QHBoxLayout *iconsLayout; QPushButton *generalButton; diff --git a/widget/widget.cpp b/widget/widget.cpp index a0d5049b3..517fc70ad 100644 --- a/widget/widget.cpp +++ b/widget/widget.cpp @@ -156,6 +156,8 @@ Widget::Widget(QWidget *parent) camera = new Camera; + settingsWidget = new SettingsWidget(camera); + // Disable some widgets until we're connected to the DHT ui->statusButton->setEnabled(false); @@ -206,6 +208,8 @@ Widget::Widget(QWidget *parent) connect(ui->settingsButton, SIGNAL(clicked()), this, SLOT(onSettingsClicked())); connect(ui->nameLabel, SIGNAL(textChanged(QString,QString)), this, SLOT(onUsernameChanged(QString,QString))); connect(ui->statusLabel, SIGNAL(textChanged(QString,QString)), this, SLOT(onStatusMessageChanged(QString,QString))); + connect(settingsWidget->identityForm, &IdentityForm::userNameChanged, core, &Core::setUsername); + connect(settingsWidget->identityForm, &IdentityForm::statusMessageChanged, core, &Core::setStatusMessage); connect(setStatusOnline, SIGNAL(triggered()), this, SLOT(setStatusOnline())); connect(setStatusAway, SIGNAL(triggered()), this, SLOT(setStatusAway())); connect(setStatusBusy, SIGNAL(triggered()), this, SLOT(setStatusBusy())); @@ -219,12 +223,12 @@ Widget::Widget(QWidget *parent) Widget::~Widget() { core->saveConfiguration(); - instance = nullptr; coreThread->exit(); coreThread->wait(500); // In case of deadlock (can happen with QtAudio/PA bugs) if (!coreThread->isFinished()) coreThread->terminate(); delete core; + delete settingsWidget; hideMainForms(); @@ -235,6 +239,7 @@ Widget::~Widget() delete g; GroupList::groupList.clear(); delete ui; + instance = nullptr; } Widget* Widget::getInstance() @@ -335,7 +340,7 @@ void Widget::onTransferClicked() void Widget::onSettingsClicked() { hideMainForms(); - settingsWidget.show(*ui); + settingsWidget->show(*ui); activeChatroomWidget = nullptr; } @@ -364,6 +369,7 @@ void Widget::setUsername(const QString& username) { ui->nameLabel->setText(username); ui->nameLabel->setToolTip(username); // for overlength names + settingsWidget->identityForm->userName->setText(username); } void Widget::onStatusMessageChanged(const QString& newStatusMessage, const QString& oldStatusMessage) @@ -377,11 +383,11 @@ void Widget::setStatusMessage(const QString &statusMessage) { ui->statusLabel->setText(statusMessage); ui->statusLabel->setToolTip(statusMessage); // for overlength messsages + settingsWidget->identityForm->statusMessage->setText(statusMessage); } void Widget::addFriend(int friendId, const QString &userId) { - qDebug() << "Widget: Adding friend with id "+userId; Friend* newfriend = FriendList::addFriend(friendId, userId); QLayout* layout = contactListWidget->getFriendLayout(Status::Offline); diff --git a/widget/widget.h b/widget/widget.h index e94435fbb..26fecb84d 100644 --- a/widget/widget.h +++ b/widget/widget.h @@ -20,6 +20,7 @@ #include #include "widget/form/addfriendform.h" #include "widget/form/settingswidget.h" +#include "widget/form/settings/identityform.h" #include "widget/form/filesform.h" #include "corestructs.h" @@ -134,7 +135,7 @@ private: Core* core; QThread* coreThread; AddFriendForm friendForm; - SettingsWidget settingsWidget; + SettingsWidget* settingsWidget; FilesForm filesForm; static Widget* instance; GenericChatroomWidget* activeChatroomWidget; From e3580fc416dd5ed298899016ba6759e320c4e264 Mon Sep 17 00:00:00 2001 From: dubslow Date: Tue, 30 Sep 2014 05:02:49 -0500 Subject: [PATCH 127/205] one frickin stinkin merge error --- qtox.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qtox.pro b/qtox.pro index ad0d839c2..68ab4db73 100644 --- a/qtox.pro +++ b/qtox.pro @@ -164,7 +164,7 @@ SOURCES += \ widget/tool/chatactions/chataction.cpp \ widget/chatareawidget.cpp \ filetransferinstance.cpp \ - corestructs.cpp + corestructs.cpp \ widget/tool/chatactions/messageaction.cpp \ widget/tool/chatactions/filetransferaction.cpp \ widget/tool/chatactions/systemmessageaction.cpp \ From f4b9c813a83c479a3982d67f01a974c2b3c3bb3f Mon Sep 17 00:00:00 2001 From: apprb Date: Wed, 1 Oct 2014 00:35:27 +0700 Subject: [PATCH 128/205] Filetransfer: speed calculation fix --- filetransferinstance.cpp | 24 +++++++++++++----------- filetransferinstance.h | 2 +- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/filetransferinstance.cpp b/filetransferinstance.cpp index 0561454b4..9ab0c75d3 100644 --- a/filetransferinstance.cpp +++ b/filetransferinstance.cpp @@ -35,6 +35,7 @@ FileTransferInstance::FileTransferInstance(ToxFile File) id = Idconter++; state = tsPending; remotePaused = false; + lastUpdateTime = QDateTime::currentDateTime(); filename = File.fileName; QFont font; @@ -76,17 +77,16 @@ void FileTransferInstance::onFileTransferInfo(int FriendId, int FileNum, int64_t return; // state = tsProcessing; - QDateTime newtime = QDateTime::currentDateTime(); - int timediff = started.secsTo(newtime); + QDateTime now = QDateTime::currentDateTime(); + if (lastUpdateTime.secsTo(now) < 1) //update every 1s + return; + + int timediff = startTime.secsTo(now); if (timediff <= 0) return; - qint64 totalbytes = BytesSent + lastBytesSent; // bytes sent so far - if (totalbytes < 0) - { - qWarning() << "FileTransferInstance::onFileTransferInfo: Negative transfer speed !"; - totalbytes = 0; - } - long rawspeed = totalbytes / timediff; + + long rawspeed = BytesSent / timediff; + speed = getHumanReadableSize(rawspeed)+"/s"; size = getHumanReadableSize(Filesize); totalBytes = Filesize; @@ -96,7 +96,8 @@ void FileTransferInstance::onFileTransferInfo(int FriendId, int FileNum, int64_t QTime etaTime(0,0); etaTime = etaTime.addSecs(etaSecs); eta = etaTime.toString("mm:ss"); - lastBytesSent = totalbytes; + lastBytesSent = BytesSent; + lastUpdateTime = now; emit stateUpdated(); } @@ -142,6 +143,7 @@ void FileTransferInstance::onFileTransferAccepted(ToxFile File) remotePaused = false; state = tsProcessing; + startTime = QDateTime::currentDateTime(); emit stateUpdated(); } @@ -221,7 +223,7 @@ void FileTransferInstance::acceptRecvRequest() Core::getInstance()->acceptFileRecvRequest(friendId, fileNum, path); state = tsProcessing; - started = QDateTime::currentDateTime(); + startTime = QDateTime::currentDateTime(); emit stateUpdated(); } diff --git a/filetransferinstance.h b/filetransferinstance.h index 0168f3c61..f32c10f92 100644 --- a/filetransferinstance.h +++ b/filetransferinstance.h @@ -74,7 +74,7 @@ private: QImage pic; QString filename, size, speed, eta; QString filenameElided; - QDateTime started; + QDateTime startTime, lastUpdateTime; long long lastBytesSent, totalBytes; int fileNum; int friendId; From 01632d2d0e5fdb977732183498e7e1402563d1fa Mon Sep 17 00:00:00 2001 From: dubslow Date: Mon, 29 Sep 2014 22:24:38 -0500 Subject: [PATCH 129/205] Create desktop file for GNU-Linux --- qTox.desktop | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 qTox.desktop diff --git a/qTox.desktop b/qTox.desktop new file mode 100644 index 000000000..afd74b440 --- /dev/null +++ b/qTox.desktop @@ -0,0 +1,12 @@ +[Desktop Entry] +Version=1.0 +Type=Application +Name=qTox +GenericName=Tox client +Comment=qTox is a powerful Tox client that follows the Tox design guidelines. +TryExec=qtox +Exec=qtox +Icon=qtox +Categories=InstantMessaging;;AudioVideo;Network; +Terminal=false +MimeType=x-scheme-handler/tox; From c6f01c31ab456e54c470c7748f8ec47efbc9a323 Mon Sep 17 00:00:00 2001 From: dubslow Date: Mon, 29 Sep 2014 22:45:33 -0500 Subject: [PATCH 130/205] add utox icons for packaging --- img/icons/qtox-128x128.png | Bin 0 -> 2595 bytes img/icons/qtox-14x14.png | Bin 0 -> 480 bytes img/icons/qtox-16x16.png | Bin 0 -> 563 bytes img/icons/qtox-192x192.png | Bin 0 -> 4059 bytes img/icons/qtox-22x22.png | Bin 0 -> 689 bytes img/icons/qtox-24x24.png | Bin 0 -> 784 bytes img/icons/qtox-256x256.png | Bin 0 -> 5630 bytes img/icons/qtox-32x32.png | Bin 0 -> 937 bytes img/icons/qtox-36x36.png | Bin 0 -> 978 bytes img/icons/qtox-48x48.png | Bin 0 -> 1299 bytes img/icons/qtox-512x512.png | Bin 0 -> 12635 bytes img/icons/qtox-64x64.png | Bin 0 -> 1549 bytes img/icons/qtox-72x72.png | Bin 0 -> 1762 bytes img/icons/qtox-96x96.png | Bin 0 -> 2182 bytes img/icons/qtox.svg | 4 ++++ 15 files changed, 4 insertions(+) create mode 100644 img/icons/qtox-128x128.png create mode 100644 img/icons/qtox-14x14.png create mode 100644 img/icons/qtox-16x16.png create mode 100644 img/icons/qtox-192x192.png create mode 100644 img/icons/qtox-22x22.png create mode 100644 img/icons/qtox-24x24.png create mode 100644 img/icons/qtox-256x256.png create mode 100644 img/icons/qtox-32x32.png create mode 100644 img/icons/qtox-36x36.png create mode 100644 img/icons/qtox-48x48.png create mode 100644 img/icons/qtox-512x512.png create mode 100644 img/icons/qtox-64x64.png create mode 100644 img/icons/qtox-72x72.png create mode 100644 img/icons/qtox-96x96.png create mode 100644 img/icons/qtox.svg diff --git a/img/icons/qtox-128x128.png b/img/icons/qtox-128x128.png new file mode 100644 index 0000000000000000000000000000000000000000..a790ae173b3c955d4af625081c4aada886478861 GIT binary patch literal 2595 zcmX|Dc{tQ-8-9OdCNl;xob3Bh6HzKl_N`{J?~)ixb!^RK8$y0eLNZ38s8F&CC84B= zLZ=cXWu1{6Bn)+!uhH?1?~m`juIIh4=f3afpZB_+`+BonoQ{Zz$cq2~#7IP2Hvz(1 zh2AE(yUhb%3ji5yP4YksP7*pKQ_y3m#ADF_Z2P`dkaDciK>;ZjW9Jj&PB|4r3yeAm zXf&E`=$Y{7;6Un0T}ssH8%w70g26J9t(8ao=;Eyes-w4JZ_TgrMUPLLhd#u4;4^)! z)p29lpNp$?^d#;5vwVFeH4D{W6b4yKs-ZnKE}^FicG%RH4|~bwR1A|o?D7rDA^zgO z?J!(Eh+pl0Iy)Y{%>TVo^lI;q$>dpn`+7;@lJPV5x;uC76uPeP`pOLkq-CLcC=RNE z)yqVyn^IF`gsM^}SiWTG0Y!`MzQ~Xl0~W}OkOHjWq}CjT?L&2fZ~0(#8yn}d-PBX< zXD#d9B$6j!kQ78*l<3plYlsOFSWKe;#rLYbzixsK61YEg9L8a~T7Lk(5*}=F*iHWo zXyZ|QVM;#OIFxWrQ=Hv@kd=#cF-&siREi6Xx&FUU=g^yGoLWX#t2;W$60r-r={Pp$ zm+nLWlbX=yt`w9}*)(@i5%Sl7{A5&fY-DHl6u0p9?^WeGT){pLO2JD9uc9o%3{caUo~z>y5C^ z@?es8VqBWJCfbqT*Q^#(Mmm%E)M1V`9XAzejlx)y;BVcHKU&{xtrHvRX>?5Wni`uQ zy8XemC#y1+2r__`&gu7W`)DMJ*+?NshWwTqW2EWsQEiLX0%e+jE}x>#&(s% zhM_}Wb?HEeBp8x95y>LEa|7>nw+fYCNR&ffCnAiHL|O~9GQ-e8Tvpm22hqVi9=3rM zy%ng>H&E^&lJI>Mrj5WxP56@WG0c%^2S-{&*pnqV0K<{sq}7SV{~rD4`~x)H+oj4v z;aF;xStY2pn0ef5`+D3~n_fbJ6rv5zzgkrw0u-We2y@dcd`%Q**#xpQa1{xn4h}>= zYXo{nSumf`ds4E@Iigf?OD$0@aqcg*pyXM>$`gs-wIC!GzD$(OBhW!xC5#-fgex73 zCp)8Nj;7p0{kimELl0*u1TizY=(@tG*_j#52g)XxvNT|%V3ZvAE94$Bb3vxH5INui z_^XZS*d1Z&R^ja7YebNPYO>!;S?Z`!?+(ao3F^2KtOa>Uv*Jv4Ez6BY3pdQ?x34=R zs5q9m!{B3jdGyPdFO%cbb6XWFdP!S!!X)_Utrhf-koV zv$;o=jef2nv1I1=b)|#re!8-<){;dAj8z|v-hBD$LPCD(6yO+1KFL>3q8$3Cjb zpFe#I%d|#(=C1#+XboApLTc#$b*wYuKgepEcm{IdK4=R>I&D(oFXe7T}dJC!d2H&P4y*6Qlems+w&;8ox}7gH_ngvbQDX)4oC z<%v6UGnWXKt9QR1uo`>G1o{kaR<%+l-R_X=z8DLLy32d0mb{^hv(%@W23!Ta6L>g; zW3S|j;L!5G0}L=p#Y%zBY$Q|EZ=3E>@INPc`?LLsb*!lkg1D`IBJoYLdZyBN_0cb} zX-j4j_#mlQ?V-_CgO*GN)^t~e%@gsRM3D7dsbf4z_VZH|_ssX-dbzv5*xA`7-#8c< zM@J6K`=(S>d&*uyO0>1nN5H;%0e@iw3!^{vt5Q$yb=`DE8 z6rmWUJAOtGe_K-5pV2Wdhz1i5VeCO4WfrfjidGxW@vCE~p`(HEY5c(~_e zz{Bx_Lt!miOdzix`R(B`-(>~G0WFRWrVMI3`%t_4Nr$Xi*iUsq-ZaJKiXQKs4sykq z(0gRS!djmyNb}afS?>K%uZ@|dQJ;q**{N=Bsy9wuK*F;6NIotloFF7 z5v8d+V?7C@$M2_(7&P4ImvMM3^rLxQXtr^L=YETrlZa8e(F yMiFf_h~f9fV$wp+gadY_k0xe&g(kyJt*MA|OVG5r^&Nr_9U$2`*)~{{)BXztB7!pj literal 0 HcmV?d00001 diff --git a/img/icons/qtox-14x14.png b/img/icons/qtox-14x14.png new file mode 100644 index 0000000000000000000000000000000000000000..54890d417ccbce8e2db95d553369d5b1e90a36a6 GIT binary patch literal 480 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh3?wzC-F*zCn2Vh}LpV4%Za?&Y0OWEOctjQh z=|dpQ=-(-G9mtR@ag8Vm&QB{TPb^AhC@(M9%goCzPEIUH)ypqRpZ(583aDsKfKQ0) z|NsA0l~vIYQ1JEZ*FeErw{F3u4jnwSchBA(+jp#8yA~)ob;{I=@`|$3vY4otFe$5>*E{X7vSpb3en~0;0RlpinR(g8$%zH2dih1^v)|cB0Tmq%@CkAK z|Np`0?Wh4jfp!c5QoGdsAamV?!fcZ&qd&gq@L=k)D>G zoRkdYh6aa11U=k5fDCI(YgZRnAj8zy)Xdb(*vQz-#LNN+P0WCTI$Ao$hQ>w)MnHz4 zz9CRVUsoT9fDAPiHBEI*AVWh<1HuK002x4Jsh)id=pBcWAirP+ZXOv$RW)@h8$0`u z(9o3BjDpsV&aR%Rv**m6J8$8JjhhY}ICSL5nG2V$T)A=g!J|h{o<4i=^3|JnA3lBh z{O9jK!#_(hfo4tfba4!k2oF7XU8u=Gfc1h#nRxX_nS9x5%omGHiU(&6!Yinq?WoW}cW?YopoR7(Scac^TiE&eg~AOS4VU{%+K@ jdDRX9F|9LFVg>5+7b^1l-`$x8bRmPMtDnm{r-UW|m&e6n literal 0 HcmV?d00001 diff --git a/img/icons/qtox-192x192.png b/img/icons/qtox-192x192.png new file mode 100644 index 0000000000000000000000000000000000000000..a9a2e5daa827c51894fc02dcfe73bc7bb36990c3 GIT binary patch literal 4059 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 literal 0 HcmV?d00001 diff --git a/img/icons/qtox-24x24.png b/img/icons/qtox-24x24.png new file mode 100644 index 0000000000000000000000000000000000000000..243c7d27cb72fb9f5c8a90204fa54429d237e79b GIT binary patch literal 784 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM3?#3wJbMaAF&8^|hH!9j+gcyqV(DCY@~py6#{%h zT>t<7ud1v{Bmye__3PK4KYzY|{|?b|<;s$QG*~L_eG*~2rxk7OM?7@85o(E zSy`lij8w{Y3ARjb#oU%zql<}KTH?%jXj z;K9R3jvPI9{KV}X)2b@5w zzI(bjhG+!mPIw;1WGK?oyqjy0fB?(NOK+5}It4E2=C~pKXwU!X9hx%cI-k|cpILjp zlXP10W$xYTXA8h(A{vsR!p}l~`~?O9gQu&X%Q~loCIA~8C+7eF literal 0 HcmV?d00001 diff --git a/img/icons/qtox-256x256.png b/img/icons/qtox-256x256.png new file mode 100644 index 0000000000000000000000000000000000000000..ea5cefa744a4ecdcb06e8e7f362ffe753ff274af GIT binary patch literal 5630 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 literal 0 HcmV?d00001 diff --git a/img/icons/qtox-32x32.png b/img/icons/qtox-32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..a33fc5df554692f88544fadd033df1d743748d5e GIT binary patch literal 937 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dy%*9TgAsieWw;%dH0CG7CJR*x3 z7#MehFr(F*$B%%5k|nMYCBgY=CFO}lsSM@i<$9TU*~Q6;1*v-ZMd`EO*+>CZM+W$W zxc>kDUsYL^JOtGH>({UE-@kwU^!eq>mq0_FK79%#A3u8h;K2ikndi=(JALZ((W6J# zuUo%j`3j)m>{+uRQV??Dgo$u&d09D-U0PBKB#R1*3JVH>jQrgE+??E;?3}F3tjvte zjI@lT#3YE8xR|);$moc$i15(xu#m9O;837=aA0tte_()L0FdqF>E-3&<>~GTWP7-I zKy*3SIRKHpt-ZaSy`8O{osFH1wT-odItuDgocGjMMuZP#Kt8gr=;Z)6KXI7K*-H zuxj1%t%;ZJ+}`^9KCh8(?RJNIc}#u^)~71mHZ@#ksd1Pi*~w@p%)#8wB*Ty>+`(|2 zX%3U1_5^9;1Hz0Sj86Y93~7G$FEhU>|Al4UkvsgiCVcSwYSy{WSh>98!iQdo`_^Cf z{ad@}xU1i}l~#PW9GCSrD^`Boy?)g~`AWG*2bA^yEbWh&lI}0+@haP6lESiPZJ{S@ zUVE**nR2Ea=(3sZP&jqtRwdqj({@X|=KD7>A+G+UFV`Na`rXebGo-U6d}p~K`d|*j zai%HeOPQxz)V=vp`EB3P-fm|06BZT$+g8*?zn?m5=J6)ixwBSZJyqYj_1iz)`X8Tx PvB}`+>gTe~DWM4fAJ}e2 literal 0 HcmV?d00001 diff --git a/img/icons/qtox-36x36.png b/img/icons/qtox-36x36.png new file mode 100644 index 0000000000000000000000000000000000000000..f51945091178c0cbdb54afcd677748e5436733ef GIT binary patch literal 978 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k3?#4J%UA`Zn2Vh}LpV4%Za?&Y0OWEOctjR6 zFfe`sVMb#HACP9r64!{5;QX|b^2DN4hVt@qz0ADq;^f4FRK5J7^x5xhq=2ep0(?ST z|NsB5s;o*L0_y$s>(`$@f4+YG`uzFxJ9qBfxN+mwty`BaUAl7R%7qIT&Ye4V^ytw; z2M--MaA5DAz5Dm=U$c76+&OdS&7C)M#!R54)22?FK5hEcDO3CV`g?nNJK8(y>*{N3 zYD*wEO>zzB$dTtj_BATrQ103wJ9 zI$AmqhPI|QkO3jJG_)Xsn(CTB1YxVIs;jA}0of4puR@dnFfxiug8YIRnE3bwgvAw< z)igBq42?}3J^g}0LPNu&h&8oZrQed$FALb_8mBM-XzMT1RVE_E4u+YHWINf|LsTNGTYl|s@(C;#%D-q5ZF zPbRCTs^_xjA8US~eWl!c`q95)X;Jou^N;RaV>o5DX4h4TnqcFjnpKA;J?Y%|DOT~# z*Ea4NXTSADzMl0G_u0c&)?ZNDxy)3POF(3TQq^NeO)I4r0bL(fNh^NuQgdHluuAgZ zan1{c`A=`N`K7#AGkea;|8Y%DU*5M|Q_W~um{}Z>#8&yQRmaWnWWbFVI#xkNSDkj- zT`x|bA!B&TY+6eDqBim3&-Xkg2JJ6YRO8>>cj}*hO{h(JvSRaJV4O2}y85}Sb4q9e E0HC*vl>h($ literal 0 HcmV?d00001 diff --git a/img/icons/qtox-48x48.png b/img/icons/qtox-48x48.png new file mode 100644 index 0000000000000000000000000000000000000000..9ab7b0174665ac2e499a473123c1d1316e1df7cb GIT binary patch literal 1299 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 KPiCF4x${4-K-t{@ literal 0 HcmV?d00001 diff --git a/img/icons/qtox-64x64.png b/img/icons/qtox-64x64.png new file mode 100644 index 0000000000000000000000000000000000000000..2ff34310bc6dedcc82ecec95c9f26a35b4a13b0d GIT binary patch literal 1549 zcmb`Gi#yY60LOnDqE*l7LPa@x4!N7l+|{wuVKSG^HbODuY%#eUTeh8HmvZaLC8Q)y zq0EHbiz9myDZ(Stg(adyl7*A&c|Cic{(|#7pZEKI-tY6izu)uxE~$7=mmLTV1O!1l zT#q{uz>MA;DhePA8U-_8QeYf&C8?;Wym^Nk1ANI=W@6lHis3qN3uGlG~*sQCWFKRdsbuZEbBsV`F1ebISwC!?yO0&Ys@B zzUKpjL$6-Fels#MB7HkHHa;;q`QhW#r|FrQ*)MbR^D^1DZwm{Hi%U!YeqUZ$U0Yvo zk}2ANUm(TR={J&ZTg%WCcbk{0@~D?Tz3f(lsQA%q%xCWJYJ-NtYcH27VsAdm>i54; zmmB&ye3!q_$KdR`z1Hl-;rpoP&F?waqwE+7QH9;Z@1>#F!WU%5cK9J_AWIZV;(0ts z3P6j+$!;B7m&`JwJPQsE^;*m+VJA50*^^3LEFJHuX-;?HtK)i=X=CAa*eaEgNOQ8| z>|sS!^>JPg2L?eM1*_CLtkb-Dhcdf<`?~i#?f#V)F3?pBjn}Otp5IgAK!!xR#as#D zWZIylw=~;@?Kp%$=Nx&;L}q$OKiOs{YnS}}Oev;wl)hJAZ|xv*RQnvq*evf`{HYsP zw|i0qUrWf{O4!aIz7oRuN*3&Tu)r!yvd2_mCP#73P+_18&hE=1^ZOy|J4Jjq1T@yx z<{+HL!l1pZXhEIpO5_@IS(C2Fx6}IA^C90wZ!t)wP+9C&0PEyNOuwM{$?~*D=3Dno zR`RC$c=;5V=e>!q!G77YM6A8zBdZKtK-KmlzMlwBGziK^+)af4f<#r{txOIU!EyIz5^+AbXV+nra6t5jF>|@a`vpf zoe)?%uI*O{=tti_8-7H0+W?AN-srLWWq09ENH=)G-j_yO-Gc;t9myo6ePc^U4Z2JR z-vPfF30vt=Er@t#n#O8IMbuQ)R^Hws4vb#Jkj2e1v>N|ctz t*9XZn>59c4Y?;QC2Q9z)o)<=&F-1q7IOLZ2SqAd`$oV literal 0 HcmV?d00001 diff --git a/img/icons/qtox-72x72.png b/img/icons/qtox-72x72.png new file mode 100644 index 0000000000000000000000000000000000000000..5d33db7f8049640f769b4c7102bb6c15b74af7ef GIT binary patch literal 1762 zcmchW=TlQz9EJlp7||$-ND&YgLg-aRgcV2v1f_%+N>E^l7$8arAu)7AG4#+yC7`e% zL5d(q39u_NR#uFmqauPVP3a?wS=r-c#t-`k?A-S}=lQ+o&fNRq-ZZSMBTPnF1_FV= zoG@q{*fBpAR0@!2j$(jKDgx<*heDyR-@8qKaR(Jchyd;Mk0sH0%H|6wmFV`~^wVJ^ zIx~QF9>QcYjY23FBF+U+&l`o&f{GWdl_3zxD_Cc|{npkNToeBP2RwIkb5kS|ZES3; zt*(I=SYBRUSXfwGTm(KnJv}os17v)Bd}3l^WMo7r6b=jw2n2$@zP{e)y$`z|c6D}j zbae3B`7JFi;LiKa_Zu1-fYjC1)z;JkspeG!R#sF3ic?xr$}Q$zzjnR&Mloov7G5nZ zD9p>v6Q5>tvVo+hrKhE)rLa@jSJ=r($%zSxm*X$T$HjxA*yz}psFxtTc-bJHI*Gcf}Z z_r`|CAVvm8U=$OGft~>f5Pe;JKs_BjF?A8TKytWO|Oju<@N!^6|d+nYe} zIdjI>*VjKFfOsx2D1?0BVrXa>l^RZ?(dn0%k&#i+(Xp{{@t0Yw#H8da?3C2>jLa-f zc1~ViUVcGgQPH*QH;TC>H_OV)Z{Mz}s=iZGQ&)fYZbM^ZQ}g}S);4~}AAdgR>FIg& z_{q~}y}iAEz36-Os=t45Xn1&JWOVfPo44;LC#R-9%+AftFMRyCxU{sqva+_ezW#aR z%h#`)o8LsDfByOYogbg127b9uPG~#4ch94t8UKD;#qG zT2tzo@FYfp6j$Dm;rXUqr)|E)@E49xW9HRwF$OpNUY|9pE~+vXb#=}#-)V>Dv8P1v zwk7VGo1rWIG(*F@1-9L#iV&8gzBI#>FzsF==jix1K^*17m7LIrDhKAyA@ds7z5ZVR z!U`m&yH6%}q3=bhmO=EEDNTh6)%p2@_R~j~gr=7eLvy2e)2t^>@e_s8CaB?M&Za1G zyvWzHGd5)~Z6$X7Xeovh)McSrkoK)L%DsM~n|40vb6mP2Zjg^)j&eCK7B`hjPnw>n zsCUM?y%|TN4zBPNNilP}=}I}`)`)oJ_40kUSs8fA4*s0O~>HS)->LF_SRHiy%v zU0Ul<(()xZ9#`}GiV>-U{C4cQ?o_rlr69`HA~V9$3Y~Gel&h@WjrK#YR#Pn(RQDzI z=MoWj9%mF*-IDRT+<8q=GZ=}Ayk@wX*bpy&qhIckc6h2EJ}A-F%mJm zU1jrt77IBY!+^Kz>bAoft65ly{YJ0(C!WPIwR{WflACN(;w)}x%gz$Gd(vx?QM)G( z=?+S;Ge1l{g|eSxc)NCmU@%hbW-a>eT^{)YO%uG0`>fXYZ73cdT4GP-oxlE)Fb{(-pGf1Rrzf{Pi0WM1#rJGBx-gghG>YDxFl^j-0<+&<2 zj;gxY!&NA;mmQ`&3S%{;(9Whk)2k(WvP66)wIOW7zh;jQF(Ycf5d7K@Cwo_PJ@U82 Fe*voy$$$U= literal 0 HcmV?d00001 diff --git a/img/icons/qtox-96x96.png b/img/icons/qtox-96x96.png new file mode 100644 index 0000000000000000000000000000000000000000..b97f35edb3de1b06e74dc45295e5ef214945fd8e GIT binary patch literal 2182 zcmd6ni8qvM9LFb14YGw4lFBl6vae-JmSmeTNHexUmcbCRlaTCOvRriS!l*7X#3;+P z(?v?mqzPdxw;D8YA7{?Ff5ScJ`+VNd@Atg#d!BQC=Y3PHtxP%Dh1ekw2&dU~V_R@V zA1x>|;PkcRqYY-9p_x4t3jIL7NdhHX;B`kF1j4F(w2rlHz>Xd|8)AYCvBP3Q!d!zr zAz@)*3O)h8ICs}TPX%nSS20yr2)qYkZE0_Ecz7srN#g$#aGw4BeL9^^qtU*9{|*ke zwY3Gfwzfv4Qh}_lu2LwJ<>h7IOP`h&78Xb(()|29DBrz%_x}BRATu*FQ&UqD6BDB& zqr*ePpffNq0NB^p_vZB*AYGkZ-LJX{1OjkIo5I zDl#H6>~2_iSU4zygMx9vIL2-Me*O&c_VV`e_F*`nhr5TTyQiD0o4cz!DABjkfT-Ij zlnV-oi?a)$vy-#4qcadkq@$Cg6A&Z=6h!0&WKfZfk98V{HS(+R7U6 zhUE<_ORFQXxB&=aVQz6mGYd0QGa#lWrhrBUMurB4Kn$)J{Ku>MSAm1*>*@pQ>F6=2 zqot#*sja1{rKO>zp{}8+uBoA>0k+iD)Pbn0s)MMhsDX~^WmP~B6=fBb%PI`NtaKR& zpt7Pe5C)YLlz=PBEB;3XIR)VIvhobd$;g2Kmz9?Yf1fjjcT#j&MLC9UUE=z!+}ba&ZB}L7~xLVjiBJ7>t*XkIx-nKY#xK zEH*F*hYJb03+5jY85tEF8y6RU|9(>H!?d(V>FF6+S=o7c`2~eVB_$=LW##4NPo7j( zR#jEk*4EY4H#9UnZES36ZfXcn zCMVxc&&SsMO7^?d_d!-+%m| z(f0QDf70o{4i55v?aP4Q!iJf#fxY*_#$!(;zYYI`0V*|sC`w>Hi5DOUw-5-*2D1w5 zyrjPs0b(Y6wk{Sh<5!tE4DM% zGVT9QU}liy=A&eE4oPc|cU#>#KIda!)|Mmf*rj9~dds5wI7T1QDpcknQ#iU_IkU~z z9&e5ie_^g_HfVq}W3(_gK1rIJL+ zOX%$DscAt4KfK8`DS2O-^J>_POYL`mLnM|zQWc#}8WQvs)~G8w9^ataW#Hk_V(<9G zAke;u+J7n}N2W#%N)>)!WQ_S;NPApvS!x$^=7%dsCuiyT-%ulGD__$*ICQIQF=?z3 zRdb0)vS3IOk|o6AGGaU z>uGOilCUvYZvM!bvP@W^$TkJ3Fc%4odi;Ld`zMF>XvHGE8oSbf)u6b2%00PPk#V9> zWB_}<_g3cmz(E8D5p_cX8XUrt3ew5*MNd()*hS2e@(k$$D`A ze6hW{M6H#Upt940lO2yscwUf~j95^O3Kt58GzN>6?~}xu(1I7jQ)R=SeD)#gUk~v7`&B&zHq*I!bnV% z(5B2L9>rSKgGm(6{qdaWpS2yfnetnA{Pq>T1~WV0b9c3f2dAphiWJP9^C?o$dMknp zZOWa^tt0L4r+ue(r}o^8^m5R0Mq>BK&{y_uY}d%pfR{}(R9tq)z={pCc4Y~|T@iu4QWwt++*W;kScJU5 zLqDc=VEzivZL7U2A;Lr5adaTBrUbpGvnM6CIJ*4eEDek+DwDxGr + + + From dd96df9940bbb85dd6c65376e79f5bf4649658a1 Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Tue, 30 Sep 2014 22:46:24 +0200 Subject: [PATCH 131/205] Fix performance regression, revert part of 87c9bbf1e6f7565bcf8aba7cb1f61dea004912e9 --- widget/adjustingscrollarea.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/widget/adjustingscrollarea.cpp b/widget/adjustingscrollarea.cpp index 2bd9cd3e8..04b735ed1 100644 --- a/widget/adjustingscrollarea.cpp +++ b/widget/adjustingscrollarea.cpp @@ -55,8 +55,9 @@ bool AdjustingScrollArea::eventFilter(QObject *obj, QEvent *ev) { // workaround: sometimes a child widget gets drawn on top of the scrollbar // so we trigger a repaint afterwards - verticalScrollBar()->update(); - horizontalScrollBar()->update(); + // => Actually, we don't. This triggers an infinite loop of QEvent::UpdateRequest and burns 100% CPU ! + //verticalScrollBar()->update(); + //horizontalScrollBar()->update(); } return QObject::eventFilter(obj, ev); From 5ccc4aa3b133c3946491ff92fdf08660977db750 Mon Sep 17 00:00:00 2001 From: Marcel Date: Tue, 30 Sep 2014 22:51:03 +0200 Subject: [PATCH 132/205] added table of content --- INSTALL.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/INSTALL.md b/INSTALL.md index 3cb777597..ed63bfe78 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -1,3 +1,10 @@ +#Install Instructions +- [Dependencies](#dependencies) +- [Windows](#windows) +- [Linux](#linux) +- [OS X](#osx) + + ##Dependencies | Name | Version | Modules | @@ -8,6 +15,7 @@ | OpenCV | >= 2.4.9 | core, highgui | | OpenAL Soft | >= 1.16.0 | | + ##Windows ###Qt @@ -68,6 +76,7 @@ make install ``` Copy the dll "OpenAL32.dll" located at "C:\qTox\libs\openal-build\install\bin" to "C:\qTox\libs\lib". Finally, copy the directory "AL" located at "C:\qTox\libs\openal-build\install\include" to "C:\qTox\libs\include". Unlike OpenCV you don't need to patch any files. Feel free to delete the directories "openal-soft-x.y.z" and "openal-build", but you don't need to. + ##Linux Most of the dependencies should be available through your package manger. You may either follow the directions below, or simply run `./simple_make.sh` after cloning, which will attempt to automatically download dependencies followed by compilation. @@ -171,6 +180,7 @@ After installing the required dependencies, run `bootstrap.sh` and then run the `buildPackages.sh` script, found in the tools folder. It will automatically get the packages necessary for building .debs, so be prepared to type your password for sudo. + ##OS X ###OSX Easy Install From 8d9d53b9e9380275ecbdbaa5b85252bdd71c878f Mon Sep 17 00:00:00 2001 From: dubslow Date: Tue, 30 Sep 2014 05:12:17 -0500 Subject: [PATCH 133/205] fix double free --- widget/form/settingswidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/widget/form/settingswidget.cpp b/widget/form/settingswidget.cpp index dddce56e0..f82e1a689 100644 --- a/widget/form/settingswidget.cpp +++ b/widget/form/settingswidget.cpp @@ -41,7 +41,7 @@ SettingsWidget::SettingsWidget(Camera* cam) prepButtons(); foot->setLayout(iconsLayout); - mainLayout = new QVBoxLayout(main); + mainLayout = new QVBoxLayout(); mainLayout->addWidget(body); mainLayout->addWidget(foot); // something something foot size From d9454d1d6e2f4637b32598c355d257f6c6eb6f15 Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Tue, 30 Sep 2014 23:34:32 +0200 Subject: [PATCH 134/205] Update package dependecies, close #355 --- debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/control b/debian/control index 7fa0cc2b4..07da3e3e4 100644 --- a/debian/control +++ b/debian/control @@ -3,7 +3,7 @@ Maintainer: John Smith Section: misc Priority: optional Standards-Version: 3.9.5 -Build-Depends: debhelper (>= 9), cdbs, qt5-qmake, libopenal-dev, libopencv-dev, libopus-dev, qtbase5-dev, sudo, autoconf, libtool, pkg-config, libvpx-dev +Build-Depends: debhelper (>= 9), cdbs, qt5-qmake, libopenal-dev (>= 1:1.15.1), libopencv-dev (>= 2.4.8), libopus-dev (>= 1.0), qtbase5-dev (>= 5.2), sudo, autoconf, libtool, pkg-config, libvpx-dev Package: qtox Architecture: any From 5b7593781973fbe0fdb348eb8dbda302bc0864bf Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Wed, 1 Oct 2014 01:39:53 +0200 Subject: [PATCH 135/205] Update win32 build config --- qtox.pro | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/qtox.pro b/qtox.pro index aa45650fd..4c4db4492 100644 --- a/qtox.pro +++ b/qtox.pro @@ -48,8 +48,9 @@ contains(JENKINS,YES) { # Rules for Windows, Mac OSX, and Linux win32 { - LIBS += -L$$PWD/libs/lib -lopencv_core249 -lopencv_highgui249 -lopencv_imgproc249 -lOpenAL32 - LIBS += $$PWD/libs/lib/libtoxav.a $$PWD/libs/lib/libopus.a $$PWD/libs/lib/libvpx.a $$PWD/libs/lib/libtoxcore.a -lws2_32 $$PWD/libs/lib/libsodium.a -lpthread -liphlpapi + LIBS += -liphlpapi -L$$PWD/libs/lib -ltoxav -ltoxcore -lvpx -lpthread + LIBS += -L$$PWD/libs/lib -lopencv_core248 -lopencv_highgui248 -lopencv_imgproc248 -lOpenAL32 -lopus + LIBS += -lz -lopengl32 -lole32 -loleaut32 -luuid -lvfw32 -ljpeg -ltiff -lpng -ljasper -lIlmImf -lHalf -lws2_32 } else { macx { LIBS += -L$$PWD/libs/lib/ -ltoxcore -ltoxav -lsodium -lvpx -framework OpenAL -lopencv_core -lopencv_highgui From 9d8e4b28f2b5e1c916892cb39371953255e669e9 Mon Sep 17 00:00:00 2001 From: dubslow Date: Sat, 13 Sep 2014 00:55:21 -0500 Subject: [PATCH 136/205] first thing's first, gotta placate the ocd --- mainwindow.ui | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mainwindow.ui b/mainwindow.ui index 385ecb489..300cc60c3 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -3115,13 +3115,13 @@ QSplitter:handle{ 0 - 60 + 57 16777215 - 60 + 57 From 3aa1c7fdedf143243f5cf2b8588a57ee3db9e99f Mon Sep 17 00:00:00 2001 From: dubslow Date: Tue, 30 Sep 2014 18:50:12 -0500 Subject: [PATCH 137/205] bootstrap tweaks --- core.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core.cpp b/core.cpp index d73b17683..15cb84a7b 100644 --- a/core.cpp +++ b/core.cpp @@ -225,9 +225,9 @@ void Core::start() * 5 disconnected; 4 were DCd for less than 20 ticks, while the 5th was ~50 ticks. * So I set the tolerance here at 25, and initial DCs should be very rare now. * This should be able to go to 50 or 100 without affecting legitimate disconnects' - * downtime, but lets be conservative for now. + * downtime, but lets be conservative for now. Edit: now 40. */ -#define CORE_DISCONNECT_TOLERANCE 25 +#define CORE_DISCONNECT_TOLERANCE 40 void Core::process() { @@ -284,7 +284,7 @@ void Core::bootstrapDht() qDebug() << "Core: Bootstraping to the DHT ..."; int i=0; - while (i < 4) + while (i < 2) // i think the more we bootstrap, the more we jitter because the more we overwrite nodes { const Settings::DhtServer& dhtServer = dhtServerList[j % listSize]; if (tox_bootstrap_from_address(tox, dhtServer.address.toLatin1().data(), From 7a2558d41a95c9e58622cab43ad347b379fde722 Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Wed, 1 Oct 2014 13:23:00 +0200 Subject: [PATCH 138/205] Fix #359 --- core.cpp | 34 +++++++++++++++++++++++++++++----- core.h | 2 +- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/core.cpp b/core.cpp index 15cb84a7b..53214dd3d 100644 --- a/core.cpp +++ b/core.cpp @@ -36,6 +36,7 @@ #include #include #include +#include const QString Core::CONFIG_FILE_NAME = "data"; QList Core::fileSendQueue; @@ -166,7 +167,13 @@ void Core::start() qsrand(time(nullptr)); - loadConfiguration(); + if (!loadConfiguration()) + { + emit failedToStart(); + tox_kill(tox); + tox = nullptr; + return; + } tox_callback_friend_request(tox, onFriendRequest, this); tox_callback_friend_message(tox, onFriendMessage, this); @@ -991,7 +998,7 @@ void Core::onFileTransferFinished(ToxFile file) emit fileDownloadFinished(file.filePath); } -void Core::loadConfiguration() +bool Core::loadConfiguration() { QString path = QDir(Settings::getSettingsDirPath()).filePath(CONFIG_FILE_NAME); @@ -999,18 +1006,34 @@ void Core::loadConfiguration() if (!configurationFile.exists()) { qWarning() << "The Tox configuration file was not found"; - return; + return true; } if (!configurationFile.open(QIODevice::ReadOnly)) { qCritical() << "File " << path << " cannot be opened"; - return; + return true; } qint64 fileSize = configurationFile.size(); if (fileSize > 0) { QByteArray data = configurationFile.readAll(); - tox_load(tox, reinterpret_cast(data.data()), data.size()); + int error = tox_load(tox, reinterpret_cast(data.data()), data.size()); + if (error < 0) + { + qWarning() << "Core: tox_load failed with error "< Date: Wed, 1 Oct 2014 14:55:48 +0200 Subject: [PATCH 139/205] Add GitHub release publishing script for Jenkins --- tools/publish.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 tools/publish.py diff --git a/tools/publish.py b/tools/publish.py new file mode 100644 index 000000000..b70ed84da --- /dev/null +++ b/tools/publish.py @@ -0,0 +1,32 @@ +#!/usr/bin/python2.7 + +from github3 import login, GitHub +from getpass import getpass, getuser +import time +import datetime +import sys +try: + import readline +except ImportError: + pass + +versionNumber = str(time.time()) +version = 'qtox-'+versionNumber +title = 'qTox '+datetime.datetime.fromtimestamp(time.time()).strftime('%Y-%m-%d %H:%M:%S') +user = "tux3" +password = "" +if password == "": + password = getpass('GitHub password for {0}: '.format(user)) + +# Obviously you could also prompt for an OAuth token +if not (user and password): + print("Cowardly refusing to login without a username and password.") + sys.exit(1) + +g = login(user, password) +repo = g.repository('tux3', 'qTox') +release = repo.create_release(version,'master',title,'This is an automated release of qTox, published by qTox\'s continous integration server.',True,False) + +if (len(sys.argv) >= 2): + file = open(sys.argv[1], 'r') + release.upload_asset('application/octet-stream',sys.argv[1],file) From c4059af010b5cf04b945602a60943ec1642c7e3b Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Wed, 1 Oct 2014 15:05:58 +0200 Subject: [PATCH 140/205] Update publish.py --- tools/publish.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/tools/publish.py b/tools/publish.py index b70ed84da..ea9624dfd 100644 --- a/tools/publish.py +++ b/tools/publish.py @@ -10,9 +10,21 @@ try: except ImportError: pass +platform='' +if (len(sys.argv) >= 3): + platform=sys.argv[2] + versionNumber = str(time.time()) -version = 'qtox-'+versionNumber -title = 'qTox '+datetime.datetime.fromtimestamp(time.time()).strftime('%Y-%m-%d %H:%M:%S') +if (platform != ''): + version = 'qtox-'+platform+'-'+versionNumber +else: + version = 'qtox-'+versionNumber +if (platform == 'windows'): + title = 'qTox Windows '+datetime.datetime.fromtimestamp(time.time()).strftime('%Y-%m-%d %H:%M:%S') +elif (platform == 'linux'): + title = 'qTox Linux '+datetime.datetime.fromtimestamp(time.time()).strftime('%Y-%m-%d %H:%M:%S') +else: + title = 'qTox '+datetime.datetime.fromtimestamp(time.time()).strftime('%Y-%m-%d %H:%M:%S') user = "tux3" password = "" if password == "": @@ -25,8 +37,9 @@ if not (user and password): g = login(user, password) repo = g.repository('tux3', 'qTox') -release = repo.create_release(version,'master',title,'This is an automated release of qTox, published by qTox\'s continous integration server.',True,False) +release = repo.create_release(version,'master',title,'This is an automated release of qTox, published by qTox\'s continous integration server.',False,False) if (len(sys.argv) >= 2): file = open(sys.argv[1], 'r') release.upload_asset('application/octet-stream',sys.argv[1],file) + From 86f9fb3ad50ef1fac2eac49079c694c97c341c52 Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Wed, 1 Oct 2014 15:38:29 +0200 Subject: [PATCH 141/205] README: Link to the new releases --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 39317b54a..430e6fcd2 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,8 @@ However, it is not a fork. This client runs on Windows, Linux and Mac natively.
+You can find the latest versions of qTox
here, or from the Tox Project's servers : + Windows download
Mac download
Linux download (click "Last successful artifacts")
From 1ccecaa80c8889ec2bf0154c73815d77f5eed6df Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Wed, 1 Oct 2014 16:05:03 +0200 Subject: [PATCH 142/205] Build both i386 and amd64 linux packages --- tools/buildPackages.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/buildPackages.sh b/tools/buildPackages.sh index 4e6b6e144..0c12e11c6 100755 --- a/tools/buildPackages.sh +++ b/tools/buildPackages.sh @@ -88,7 +88,8 @@ mv qTox-master $VERNAME # Build packages cd $VERNAME ./bootstrap.sh -debuild -us -uc +debuild -us -uc -aamd64 +debuild -us -uc -ai386 cd .. # alien warns that it should probably be run as root... From 4d916951692b0cc471bb3b8ec0ad7641f3e1b1e8 Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Wed, 1 Oct 2014 16:30:04 +0200 Subject: [PATCH 143/205] Update package dependencies --- debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/control b/debian/control index 07da3e3e4..af90ab856 100644 --- a/debian/control +++ b/debian/control @@ -7,7 +7,7 @@ Build-Depends: debhelper (>= 9), cdbs, qt5-qmake, libopenal-dev (>= 1:1.15.1), l Package: qtox Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends} +Depends: libc6 (>= 2.17), libgcc1 (>= 1:4.1.1), libgl1-mesa-glx | libgl1, libopenal1 (>= 1.14), libopencv-core2.4, libopencv-highgui2.4, libopus0 (>= 1.0), libqt5core5a (>= 5.2), libqt5gui5 (>= 5.2), libqt5network5 (>= 5.0), libqt5widgets5 (>= 5.2), libqt5xml5 (>= 5.0), libstdc++6 (>= 4.9), libvpx1 (>= 1.0.0) Description: Tox client qTox is a powerful Tox client that follows the Tox design guidelines. Tox is a decentralized and encrypted replacement for Skype, supporting From c260a7a100684504a315685cef72b4d197ea8d82 Mon Sep 17 00:00:00 2001 From: krepa098 Date: Mon, 29 Sep 2014 20:18:03 +0200 Subject: [PATCH 144/205] MaskablePixmapWidget: auto-detect a suitable background color --- widget/friendwidget.cpp | 1 + widget/groupwidget.cpp | 6 ++-- widget/maskablepixmapwidget.cpp | 57 ++++++++++++++++++++++++++++++--- widget/maskablepixmapwidget.h | 5 ++- 4 files changed, 61 insertions(+), 8 deletions(-) diff --git a/widget/friendwidget.cpp b/widget/friendwidget.cpp index ad16ac75c..32971b098 100644 --- a/widget/friendwidget.cpp +++ b/widget/friendwidget.cpp @@ -202,6 +202,7 @@ void FriendWidget::onAvatarChange(int FriendId, const QPixmap& pic) isDefaultAvatar = false; avatar->setPixmap(pic); + avatar->autopickBackground(); } void FriendWidget::onAvatarRemoved(int FriendId) diff --git a/widget/groupwidget.cpp b/widget/groupwidget.cpp index d803063ce..949fefbdc 100644 --- a/widget/groupwidget.cpp +++ b/widget/groupwidget.cpp @@ -39,8 +39,8 @@ GroupWidget::GroupWidget(int GroupId, QString Name) textLayout.setMargin(0); setLayoutDirection(Qt::LeftToRight); // parent might have set Qt::RightToLeft - avatar = new MaskablePixmapWidget(this, QSize(40,40), QString(), Qt::transparent); - avatar->setPixmap(QPixmap(":img/group.png")); + avatar = new MaskablePixmapWidget(this, QSize(40,40), ":/img/avatar_mask.png"); + avatar->setPixmap(QPixmap(":img/group_dark.png")); statusPic.setPixmap(QPixmap(":img/status/dot_online.png")); name.setText(Name); QFont small; @@ -139,7 +139,7 @@ void GroupWidget::setAsInactiveChatroom() QPalette pal3; pal3.setColor(QPalette::Background, QColor(65,65,65,255)); this->setPalette(pal3); - avatar->setPixmap(QPixmap(":img/group.png")); + avatar->setPixmap(QPixmap(":img/group_dark.png")); } void GroupWidget::updateStatusLight() diff --git a/widget/maskablepixmapwidget.cpp b/widget/maskablepixmapwidget.cpp index 90eaf9552..8cdf5d21b 100644 --- a/widget/maskablepixmapwidget.cpp +++ b/widget/maskablepixmapwidget.cpp @@ -17,10 +17,11 @@ #include "maskablepixmapwidget.h" #include -MaskablePixmapWidget::MaskablePixmapWidget(QWidget *parent, QSize size, QString maskName, QColor background) +MaskablePixmapWidget::MaskablePixmapWidget(QWidget *parent, QSize size, QString maskName, bool autopickBackground) : QWidget(parent) - , backgroundColor(background) + , backgroundColor(Qt::white) , clickable(false) + , autoBackground(autopickBackground) { setFixedSize(size); @@ -30,6 +31,47 @@ MaskablePixmapWidget::MaskablePixmapWidget(QWidget *parent, QSize size, QString mask = QPixmap(maskName).scaled(size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); } +void MaskablePixmapWidget::autopickBackground() +{ + QImage pic = pixmap.toImage(); + + if (pic.isNull()) + return; + + qreal r = 0.0f; + qreal g = 0.0f; + qreal b = 0.0f; + float weight = 1.0f; + + for (int x=0;xclickable = clickable; @@ -42,8 +84,15 @@ void MaskablePixmapWidget::setClickable(bool clickable) void MaskablePixmapWidget::setPixmap(const QPixmap &pmap) { - pixmap = pmap.scaled(width(), height(), Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation); - update(); + if (!pmap.isNull()) + { + pixmap = pmap.scaled(width(), height(), Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation); + + if (autoBackground) + autopickBackground(); + + update(); + } } QPixmap MaskablePixmapWidget::getPixmap() const diff --git a/widget/maskablepixmapwidget.h b/widget/maskablepixmapwidget.h index c4601d227..d3e8d3616 100644 --- a/widget/maskablepixmapwidget.h +++ b/widget/maskablepixmapwidget.h @@ -23,8 +23,10 @@ class MaskablePixmapWidget : public QWidget { Q_OBJECT public: - MaskablePixmapWidget(QWidget *parent, QSize size, QString maskName, QColor background = Qt::white); + MaskablePixmapWidget(QWidget *parent, QSize size, QString maskName = QString(), bool autopickBackground = true); + void autopickBackground(); + void setBackground(QColor color); void setClickable(bool clickable); void setPixmap(const QPixmap &pmap); QPixmap getPixmap() const; @@ -43,6 +45,7 @@ private: QString maskName; QColor backgroundColor; bool clickable; + bool autoBackground; }; #endif // MASKABLEPIXMAPWIDGET_H From a4cd2d34db375660399247db4a17b368a56bb9d5 Mon Sep 17 00:00:00 2001 From: krepa098 Date: Tue, 30 Sep 2014 20:10:42 +0200 Subject: [PATCH 145/205] cleanup, applied some of the "Tox User Interface Guidelines" --- misc/style.cpp | 43 ++++++++++++++- misc/style.h | 30 ++++++++++- ui/emoticonWidget/dot_page.png | Bin 233 -> 216 bytes ui/emoticonWidget/dot_page_current.png | Bin 263 -> 234 bytes ui/emoticonWidget/dot_page_hover.png | Bin 237 -> 233 bytes ui/emoticonWidget/emoticonWidget.css | 4 +- widget/emoticonswidget.cpp | 2 +- widget/form/chatform.cpp | 11 +++- widget/form/genericchatform.cpp | 24 +++++---- widget/form/groupchatform.cpp | 9 +++- widget/friendwidget.cpp | 71 +++++++++++++----------- widget/genericchatroomwidget.cpp | 48 ++++++++--------- widget/genericchatroomwidget.h | 8 +-- widget/groupwidget.cpp | 72 +++++++++++++------------ widget/maskablepixmapwidget.cpp | 37 ++++++++----- widget/maskablepixmapwidget.h | 4 +- widget/widget.cpp | 12 +++-- 17 files changed, 241 insertions(+), 134 deletions(-) diff --git a/misc/style.cpp b/misc/style.cpp index 609dcc277..0801cf154 100644 --- a/misc/style.cpp +++ b/misc/style.cpp @@ -19,8 +19,9 @@ #include #include +#include -QString Style::get(const QString &filename) +QString Style::getStylesheet(const QString &filename) { if (!Settings::getInstance().getUseNativeStyle()) { @@ -28,8 +29,46 @@ QString Style::get(const QString &filename) if (file.open(QFile::ReadOnly | QFile::Text)) return file.readAll(); else - qWarning() << "Style " << filename << " not found"; + qWarning() << "Stylesheet " << filename << " not found"; } return QString(); } + +QColor Style::getColor(Style::ColorPalette entry) +{ + static QColor palette[] = { + QColor("#6bc260"), + QColor("#cebf44"), + QColor("#c84e4e"), + QColor("#000000"), + QColor("#1c1c1c"), + QColor("#414141"), + QColor("#d1d1d1"), + QColor("#ffffff"), + }; + + return palette[entry]; +} + +QFont appFont(int pixelSize, int weight) { + auto font = QFont(); + font.setPixelSize(pixelSize); + font.setWeight(weight); + return font; +} + +QFont Style::getFont(Style::Font font) +{ + static QFont fonts[] = { + appFont(14, QFont::Bold), + appFont(12, QFont::Normal), + appFont(12, QFont::Bold), + appFont(11, QFont::Normal), + appFont(11, QFont::Bold), + appFont(10, QFont::Normal), + appFont(10, QFont::Light), + }; + + return fonts[font]; +} diff --git a/misc/style.h b/misc/style.h index 4bd42d77f..326972d92 100644 --- a/misc/style.h +++ b/misc/style.h @@ -17,12 +17,40 @@ #ifndef STYLE_H #define STYLE_H +#include +#include + class QString; class Style { public: - static QString get(const QString& filename); + enum ColorPalette + { + Green, + Yellow, + Red, + Black, + DarkGrey, + MediumGrey, + LightGrey, + White, + }; + + enum Font + { + ExtraBig, // 14px, bold + Big, // 12px + BigBold, // 12px, bold + Medium, // 11px + MediumBold, // 11px, bold + Small, // 10px + SmallLight // 10px, light + }; + + static QString getStylesheet(const QString& filename); + static QColor getColor(ColorPalette entry); + static QFont getFont(Font font); private: Style(); }; diff --git a/ui/emoticonWidget/dot_page.png b/ui/emoticonWidget/dot_page.png index c7c2aa172e2a03a298bf6f7f21c55384fc0617d4..e74d514e21cf6a0a7f3fa6f87fca8d11224d0f55 100644 GIT binary patch delta 142 zcmV;90CE560oVbMQhx~^5(N+@R0bUY003o4L_t&-(~Xcj3V<*WM8~w=Oc4CsN3gc= zND_NJij9Khv)MopjCnBC4!b)e89)!Lz+v)0rx;-7nTMF8EA)8+=$-Z)U%)l5y&iMi)po!=Q%#s!W3uy$dlo=%5ESjF| z(|ODtksN3%#FJBr1K$eo<3L{__AY4y9y`)q(#r~mpCft$lNh8G;17Dj9C>iHTcZE~ N002ovPDHLkV1lUoKeYe= diff --git a/ui/emoticonWidget/dot_page_current.png b/ui/emoticonWidget/dot_page_current.png index aa101903afbe49b8301478ab8d62053662ad07a4..7b18c42c216e4043588c1dd827246efc81f62347 100644 GIT binary patch delta 160 zcmV;R0AK%y0_p*fQhx~^5(YRp%>5()004JML_t&-(~XcZ3WHD(MBm@@xJ^P1BA#P0 z&DMdmUogRIh!%kyA`lxdWV5B{f93F)fk_0znj4@6s)$zLZR!(13aJO~?9-XLr)U~E zrk0pHqZQy%AYO$+1Xv2ZzW}*F%wp;v;CUcDO#Pd74!=e80~ubXJ_BqW7#z+n{nqaQ O0000c%>pFBCD7h`NBweCLZ(_PZ8>$($w0P4El zy8E2ZHfFX|jIjZZ{5A`cTK;Q;yN@%*Ngz{@bj$dz0a#~@>oy{#^sK5X0Mjqi%FGT0 rKuYOcmgPgz5EuY2-~uenY!C1TL+vY1V!_+~00000NkvXXu0mjf17=jA diff --git a/ui/emoticonWidget/dot_page_hover.png b/ui/emoticonWidget/dot_page_hover.png index 1c23931b921ef2be1841c3404062acc16234ebcc..822dbb6c62fa37a722652a85770df1f574d56373 100644 GIT binary patch delta 159 zcmV;Q0AT;^0qFsdQhx~^5(hW2Xwmcl004GLL_t&-(~XcZ3c^4XMBo3XnIe_qK|&6) zHr9e|0w(teNfF2)1Z`~gI5xjr;=Xct%)l5y&bb2;&_whFCP@o`h4cijlo=%5EShGH zX+7rtksLTxh-aq~2R;?v+kw79>|N3ZJPxG0q}>XKUm|(|qZp(W;0MEY95-u3c#Qx6 N002ovPDHLkV1i`1K#2eV delta 163 zcmV;U09^m+0qp^hQhx{v4FWi+!8H{C004SPL_t&-(~XcZ3Iah81gqyU7a1u&3aM{}mo1z<9B;EeE0R~`^(F9z>bq7#NXJAX2Q@D1@ zrWsetText(f->getName()); - avatar->setPixmap(QPixmap(":/img/contact_dark.png")); + + avatar->setPixmap(QPixmap(":/img/contact_dark.png"), Qt::transparent); statusMessageLabel = new CroppingLabel(); + statusMessageLabel->setFont(Style::getFont(Style::Medium)); + QPalette pal; pal.setColor(QPalette::WindowText, Style::getColor(Style::MediumGrey)); + statusMessageLabel->setPalette(pal); + netcam = new NetCamView(); headTextLayout->addWidget(statusMessageLabel); headTextLayout->addStretch(); + headTextLayout->setSpacing(0); connect(Core::getInstance(), &Core::fileSendStarted, this, &ChatForm::startFileSend); connect(Core::getInstance(), &Core::videoFrameReceived, netcam, &NetCamView::updateDisplay); @@ -507,5 +514,5 @@ void ChatForm::onAvatarRemoved(int FriendId) if (FriendId != f->friendId) return; - avatar->setPixmap(QPixmap(":/img/contact_dark.png")); + avatar->setPixmap(QPixmap(":/img/contact_dark.png"), Qt::transparent); } diff --git a/widget/form/genericchatform.cpp b/widget/form/genericchatform.cpp index 26bd958ba..2abdd0def 100644 --- a/widget/form/genericchatform.cpp +++ b/widget/form/genericchatform.cpp @@ -36,6 +36,10 @@ GenericChatForm::GenericChatForm(QWidget *parent) : headWidget = new QWidget(); nameLabel = new CroppingLabel(); + nameLabel->setFont(Style::getFont(Style::MediumBold)); + QPalette pal; pal.setColor(QPalette::WindowText, Style::getColor(Style::DarkGrey)); + nameLabel->setPalette(pal); + avatar = new MaskablePixmapWidget(this, QSize(40,40), ":/img/avatar_mask.png"); QHBoxLayout *headLayout = new QHBoxLayout(), *mainFootLayout = new QHBoxLayout(); headTextLayout = new QVBoxLayout(); @@ -43,8 +47,8 @@ GenericChatForm::GenericChatForm(QWidget *parent) : QVBoxLayout *footButtonsSmall = new QVBoxLayout(), *volMicLayout = new QVBoxLayout(); chatWidget = new ChatAreaWidget(); - chatWidget->document()->setDefaultStyleSheet(Style::get(":ui/chatArea/innerStyle.css")); - chatWidget->setStyleSheet(Style::get(":/ui/chatArea/chatArea.css")); + chatWidget->document()->setDefaultStyleSheet(Style::getStylesheet(":ui/chatArea/innerStyle.css")); + chatWidget->setStyleSheet(Style::getStylesheet(":/ui/chatArea/chatArea.css")); msgEdit = new ChatTextEdit(); @@ -63,25 +67,25 @@ GenericChatForm::GenericChatForm(QWidget *parent) : footButtonsSmall->setSpacing(2); - msgEdit->setStyleSheet(Style::get(":/ui/msgEdit/msgEdit.css")); + msgEdit->setStyleSheet(Style::getStylesheet(":/ui/msgEdit/msgEdit.css")); msgEdit->setFixedHeight(50); msgEdit->setFrameStyle(QFrame::NoFrame); - sendButton->setStyleSheet(Style::get(":/ui/sendButton/sendButton.css")); - fileButton->setStyleSheet(Style::get(":/ui/fileButton/fileButton.css")); - emoteButton->setStyleSheet(Style::get(":/ui/emoteButton/emoteButton.css")); + sendButton->setStyleSheet(Style::getStylesheet(":/ui/sendButton/sendButton.css")); + fileButton->setStyleSheet(Style::getStylesheet(":/ui/fileButton/fileButton.css")); + emoteButton->setStyleSheet(Style::getStylesheet(":/ui/emoteButton/emoteButton.css")); callButton->setObjectName("green"); - callButton->setStyleSheet(Style::get(":/ui/callButton/callButton.css")); + callButton->setStyleSheet(Style::getStylesheet(":/ui/callButton/callButton.css")); videoButton->setObjectName("green"); - videoButton->setStyleSheet(Style::get(":/ui/videoButton/videoButton.css")); + videoButton->setStyleSheet(Style::getStylesheet(":/ui/videoButton/videoButton.css")); - QString volButtonStylesheet = Style::get(":/ui/volButton/volButton.css"); + QString volButtonStylesheet = Style::getStylesheet(":/ui/volButton/volButton.css"); volButton->setObjectName("green"); volButton->setStyleSheet(volButtonStylesheet); - QString micButtonStylesheet = Style::get(":/ui/micButton/micButton.css"); + QString micButtonStylesheet = Style::getStylesheet(":/ui/micButton/micButton.css"); micButton->setObjectName("green"); micButton->setStyleSheet(micButtonStylesheet); diff --git a/widget/form/groupchatform.cpp b/widget/form/groupchatform.cpp index 7622f2cf0..5c3253afe 100644 --- a/widget/form/groupchatform.cpp +++ b/widget/form/groupchatform.cpp @@ -21,6 +21,7 @@ #include "widget/croppinglabel.h" #include "widget/maskablepixmapwidget.h" #include "core.h" +#include "style.h" #include #include #include @@ -41,9 +42,13 @@ GroupChatForm::GroupChatForm(Group* chatGroup) small.setPixelSize(10); nameLabel->setText(group->widget->name.text()); - nusersLabel->setFont(small); + + nusersLabel->setFont(Style::getFont(Style::Medium)); nusersLabel->setText(GroupChatForm::tr("%1 users in chat","Number of users in chat").arg(group->peers.size())); - avatar->setPixmap(QPixmap(":/img/group_dark.png")); + QPalette pal; pal.setColor(QPalette::WindowText, Style::getColor(Style::MediumGrey)); + nusersLabel->setPalette(pal); + + avatar->setPixmap(QPixmap(":/img/group_dark.png"), Qt::transparent); QString names; for (QString& s : group->peers) diff --git a/widget/friendwidget.cpp b/widget/friendwidget.cpp index 32971b098..be83930ec 100644 --- a/widget/friendwidget.cpp +++ b/widget/friendwidget.cpp @@ -23,6 +23,7 @@ #include "core.h" #include "widget/form/chatform.h" #include "widget/maskablepixmapwidget.h" +#include "style.h" #include #include #include @@ -31,7 +32,8 @@ #include FriendWidget::FriendWidget(int FriendId, QString id) - : friendId(FriendId), isDefaultAvatar{true} + : friendId(FriendId) + , isDefaultAvatar{true} { setMouseTracking(true); setAutoFillBackground(true); @@ -45,22 +47,28 @@ FriendWidget::FriendWidget(int FriendId, QString id) setLayoutDirection(Qt::LeftToRight); // parent might have set Qt::RightToLeft avatar = new MaskablePixmapWidget(this, QSize(40,40), ":/img/avatar_mask.png"); - avatar->setPixmap(QPixmap(":img/contact_dark.png")); + avatar->setPixmap(QPixmap(":img/contact.png"), Qt::transparent); + name.setText(id); //statusPic.setAlignment(Qt::AlignHCenter); statusPic.setPixmap(QPixmap(":img/status/dot_away.png")); - QFont small; - small.setPixelSize(10); - statusMessage.setFont(small); + + // status text QPalette pal; - pal.setColor(QPalette::WindowText,Qt::gray); + pal.setColor(QPalette::WindowText, Style::getColor(Style::LightGrey)); statusMessage.setPalette(pal); + statusMessage.setFont(Style::getFont(Style::Medium)); + + // name text QPalette pal2; - pal2.setColor(QPalette::WindowText,Qt::white); + pal2.setColor(QPalette::WindowText, Style::getColor(Style::White)); name.setPalette(pal2); + name.setFont(Style::getFont(Style::Big)); + + // background QPalette pal3; - pal3.setColor(QPalette::Background, QColor(65,65,65,255)); - this->setPalette(pal3); + pal3.setColor(QPalette::Background, Style::getColor(Style::MediumGrey)); + setPalette(pal3); textLayout.addStretch(); textLayout.addWidget(&name); @@ -69,13 +77,11 @@ FriendWidget::FriendWidget(int FriendId, QString id) layout.addSpacing(20); layout.addWidget(avatar); - layout.addSpacing(5); + layout.addSpacing(10); layout.addLayout(&textLayout); - layout.addSpacing(5); + layout.addSpacing(10); layout.addWidget(&statusPic); - layout.addSpacing(5); - - isActiveWidget = 0; + layout.addSpacing(10); layout.invalidate(); layout.update(); @@ -126,38 +132,39 @@ void FriendWidget::contextMenuEvent(QContextMenuEvent * event) void FriendWidget::setAsActiveChatroom() { - isActiveWidget = 1; + setActive(true); - QFont small; - small.setPixelSize(10); - statusMessage.setFont(small); + // status QPalette pal; - pal.setColor(QPalette::WindowText,Qt::darkGray); + pal.setColor(QPalette::WindowText, Style::getColor(Style::MediumGrey)); statusMessage.setPalette(pal); + + // name QPalette pal2; - pal2.setColor(QPalette::WindowText,Qt::black); + pal2.setColor(QPalette::WindowText, Style::getColor(Style::DarkGrey)); name.setPalette(pal2); - QPalette pal3; - pal3.setColor(QPalette::Background, Qt::white); - this->setPalette(pal3); + + if (isDefaultAvatar) + avatar->setPixmap(QPixmap(":img/contact_dark.png"), Qt::transparent); } void FriendWidget::setAsInactiveChatroom() { - isActiveWidget = 0; + setActive(false); - QFont small; - small.setPixelSize(10); - statusMessage.setFont(small); + // status QPalette pal; - pal.setColor(QPalette::WindowText,Qt::gray); + pal.setColor(QPalette::WindowText, Style::getColor(Style::LightGrey)); statusMessage.setPalette(pal); + + // name QPalette pal2; - pal2.setColor(QPalette::WindowText,Qt::white); + pal2.setColor(QPalette::WindowText, Style::getColor(Style::White)); name.setPalette(pal2); QPalette pal3; - pal3.setColor(QPalette::Background, QColor(65,65,65,255)); - this->setPalette(pal3); + + if (isDefaultAvatar) + avatar->setPixmap(QPixmap(":img/contact.png"), Qt::transparent); } void FriendWidget::updateStatusLight() @@ -211,7 +218,7 @@ void FriendWidget::onAvatarRemoved(int FriendId) return; isDefaultAvatar = true; - avatar->setPixmap(QPixmap(":img/contact_dark.png")); + avatar->setPixmap(QPixmap(":img/contact.png"), Qt::transparent); } void FriendWidget::mousePressEvent(QMouseEvent *ev) diff --git a/widget/genericchatroomwidget.cpp b/widget/genericchatroomwidget.cpp index 234da1222..224c8f463 100644 --- a/widget/genericchatroomwidget.cpp +++ b/widget/genericchatroomwidget.cpp @@ -15,55 +15,55 @@ */ #include "genericchatroomwidget.h" +#include "style.h" #include -GenericChatroomWidget::GenericChatroomWidget(QWidget *parent) : - QWidget(parent) +GenericChatroomWidget::GenericChatroomWidget(QWidget *parent) + : QWidget(parent) + , isActiveWidget(false) { } -int GenericChatroomWidget::isActive() +bool GenericChatroomWidget::isActive() { return isActiveWidget; } -void GenericChatroomWidget::mousePressEvent(QMouseEvent *event) +void GenericChatroomWidget::setActive(bool active) { - if ((event->buttons() & Qt::LeftButton) == Qt::LeftButton) + isActiveWidget = active; + + if (active) { - if (isActive()) - { - QPalette pal; - pal.setColor(QPalette::Background, QColor(250,250,250,255)); - this->setPalette(pal); - } - else - { - QPalette pal; - pal.setColor(QPalette::Background, QColor(85,85,85,255)); - this->setPalette(pal); - } + QPalette pal; + pal.setColor(QPalette::Background, Style::getColor(Style::White)); + setPalette(pal); + } + else + { + QPalette pal; + pal.setColor(QPalette::Background, Style::getColor(Style::MediumGrey)); + setPalette(pal); } } void GenericChatroomWidget::leaveEvent(QEvent *) { - if (isActive() != 1) + if (!isActive()) { QPalette pal; - pal.setColor(QPalette::Background, lastColor); - this->setPalette(pal); + pal.setColor(QPalette::Background, Style::getColor(Style::MediumGrey)); + setPalette(pal); } } void GenericChatroomWidget::enterEvent(QEvent *) { - if (isActive() != 1) + if (!isActive()) { QPalette pal; - pal.setColor(QPalette::Background, QColor(75,75,75,255)); - lastColor = this->palette().background().color(); - this->setPalette(pal); + pal.setColor(QPalette::Background, Style::getColor(Style::MediumGrey).lighter(120)); + setPalette(pal); } } diff --git a/widget/genericchatroomwidget.h b/widget/genericchatroomwidget.h index 14e46c16e..84b1f2669 100644 --- a/widget/genericchatroomwidget.h +++ b/widget/genericchatroomwidget.h @@ -30,7 +30,6 @@ class GenericChatroomWidget : public QWidget Q_OBJECT public: GenericChatroomWidget(QWidget *parent = 0); - void mousePressEvent(QMouseEvent *event); void mouseReleaseEvent (QMouseEvent* event); void leaveEvent(QEvent *); void enterEvent(QEvent *); @@ -41,15 +40,18 @@ public: virtual void setChatForm(Ui::MainWindow &){;} virtual void resetEventFlags(){;} - int isActive(); + bool isActive(); + void setActive(bool active); signals: void chatroomWidgetClicked(GenericChatroomWidget* widget); public slots: +private: + bool isActiveWidget; + protected: - int isActiveWidget; QColor lastColor; QHBoxLayout layout; QVBoxLayout textLayout; diff --git a/widget/groupwidget.cpp b/widget/groupwidget.cpp index 949fefbdc..d2af2ba4c 100644 --- a/widget/groupwidget.cpp +++ b/widget/groupwidget.cpp @@ -20,6 +20,7 @@ #include "misc/settings.h" #include "widget/form/groupchatform.h" #include "widget/maskablepixmapwidget.h" +#include "style.h" #include #include #include @@ -40,21 +41,28 @@ GroupWidget::GroupWidget(int GroupId, QString Name) setLayoutDirection(Qt::LeftToRight); // parent might have set Qt::RightToLeft avatar = new MaskablePixmapWidget(this, QSize(40,40), ":/img/avatar_mask.png"); - avatar->setPixmap(QPixmap(":img/group_dark.png")); + avatar->setPixmap(QPixmap(":img/group.png"), Qt::transparent); + statusPic.setPixmap(QPixmap(":img/status/dot_online.png")); - name.setText(Name); - QFont small; - small.setPixelSize(10); - nusers.setFont(small); - QPalette pal; - pal.setColor(QPalette::WindowText,Qt::gray); - nusers.setPalette(pal); + + // name QPalette pal2; - pal2.setColor(QPalette::WindowText,Qt::white); + pal2.setColor(QPalette::WindowText, Style::getColor(Style::White)); name.setPalette(pal2); + name.setText(Name); + name.setFont(Style::getFont(Style::Big)); + + // status + QPalette pal; + pal.setColor(QPalette::WindowText, Style::getColor(Style::LightGrey)); + nusers.setPalette(pal); + nusers.setFont(Style::getFont(Style::Medium)); + + // background QPalette pal3; - pal3.setColor(QPalette::Background, QColor(65,65,65,255)); + pal3.setColor(QPalette::Background, Style::getColor(Style::MediumGrey)); this->setPalette(pal3); + Group* g = GroupList::findGroup(groupId); if (g) nusers.setText(GroupWidget::tr("%1 users in chat").arg(g->peers.size())); @@ -68,14 +76,12 @@ GroupWidget::GroupWidget(int GroupId, QString Name) layout.addSpacing(20); layout.addWidget(avatar); - layout.addSpacing(5); + layout.addSpacing(10); layout.addLayout(&textLayout); layout.addStretch(); - layout.addSpacing(5); + layout.addSpacing(10); layout.addWidget(&statusPic); - layout.addSpacing(5); - - isActiveWidget = 0; + layout.addSpacing(10); } void GroupWidget::contextMenuEvent(QContextMenuEvent * event) @@ -106,40 +112,36 @@ void GroupWidget::onUserListChanged() void GroupWidget::setAsActiveChatroom() { - isActiveWidget = 1; + setActive(true); - QFont small; - small.setPixelSize(10); - nusers.setFont(small); + // status QPalette pal; - pal.setColor(QPalette::WindowText,Qt::darkGray); + pal.setColor(QPalette::WindowText, Style::getColor(Style::MediumGrey)); nusers.setPalette(pal); + + // name QPalette pal2; - pal2.setColor(QPalette::WindowText,Qt::black); + pal2.setColor(QPalette::WindowText, Style::getColor(Style::DarkGrey)); name.setPalette(pal2); - QPalette pal3; - pal3.setColor(QPalette::Background, Qt::white); - this->setPalette(pal3); - avatar->setPixmap(QPixmap(":img/group_dark.png")); + + avatar->setPixmap(QPixmap(":img/group_dark.png"), Qt::transparent); } void GroupWidget::setAsInactiveChatroom() { - isActiveWidget = 0; + setActive(false); - QFont small; - small.setPixelSize(10); - nusers.setFont(small); + // status QPalette pal; - pal.setColor(QPalette::WindowText,Qt::gray); + pal.setColor(QPalette::WindowText, Style::getColor(Style::LightGrey)); nusers.setPalette(pal); + + // name QPalette pal2; - pal2.setColor(QPalette::WindowText,Qt::white); + pal2.setColor(QPalette::WindowText, Style::getColor(Style::White)); name.setPalette(pal2); - QPalette pal3; - pal3.setColor(QPalette::Background, QColor(65,65,65,255)); - this->setPalette(pal3); - avatar->setPixmap(QPixmap(":img/group_dark.png")); + + avatar->setPixmap(QPixmap(":img/group.png"), Qt::transparent); } void GroupWidget::updateStatusLight() diff --git a/widget/maskablepixmapwidget.cpp b/widget/maskablepixmapwidget.cpp index 8cdf5d21b..185494147 100644 --- a/widget/maskablepixmapwidget.cpp +++ b/widget/maskablepixmapwidget.cpp @@ -17,11 +17,10 @@ #include "maskablepixmapwidget.h" #include -MaskablePixmapWidget::MaskablePixmapWidget(QWidget *parent, QSize size, QString maskName, bool autopickBackground) +MaskablePixmapWidget::MaskablePixmapWidget(QWidget *parent, QSize size, QString maskName) : QWidget(parent) , backgroundColor(Qt::white) , clickable(false) - , autoBackground(autopickBackground) { setFixedSize(size); @@ -38,29 +37,30 @@ void MaskablePixmapWidget::autopickBackground() if (pic.isNull()) return; - qreal r = 0.0f; - qreal g = 0.0f; - qreal b = 0.0f; - float weight = 1.0f; + int r = 0; + int g = 0; + int b = 0; + int weight = 0; for (int x=0;xlayout()->setContentsMargins(0, 0, 0, 0); ui->friendList->setObjectName("friendList"); - ui->friendList->setStyleSheet(Style::get(":ui/friendList/friendList.css")); + ui->friendList->setStyleSheet(Style::getStylesheet(":ui/friendList/friendList.css")); } else { this->setObjectName("activeWindow"); - this->setStyleSheet(Style::get(":ui/window/window.css")); + this->setStyleSheet(Style::getStylesheet(":ui/window/window.css")); ui->statusPanel->setStyleSheet(QString("")); ui->friendList->setStyleSheet(QString("")); ui->friendList->setObjectName("friendList"); - ui->friendList->setStyleSheet(Style::get(":ui/friendList/friendList.css")); + ui->friendList->setStyleSheet(Style::getStylesheet(":ui/friendList/friendList.css")); ui->tbMenu->setIcon(QIcon(":ui/window/applicationIcon.png")); ui->pbMin->setObjectName("minimizeButton"); @@ -116,6 +116,7 @@ Widget::Widget(QWidget *parent) profilePicture->setPixmap(QPixmap(":/img/contact_dark.png")); profilePicture->setClickable(true); ui->horizontalLayout_3->insertWidget(0,profilePicture); + ui->horizontalLayout_3->insertSpacing(1, 7); ui->mainContent->setLayout(new QVBoxLayout()); ui->mainHead->setLayout(new QVBoxLayout()); @@ -129,13 +130,16 @@ Widget::Widget(QWidget *parent) ui->nameLabel->setEditable(true); ui->statusLabel->setEditable(true); + ui->statusLabel->setFont(Style::getFont(Style::Medium)); + ui->nameLabel->setFont(Style::getFont(Style::ExtraBig)); + // delay setting username and message until Core inits //ui->nameLabel->setText(core->getUsername()); ui->nameLabel->setStyleSheet("QLabel { color : white; font-size: 11pt; font-weight:bold;}"); //ui->statusLabel->setText(core->getStatusMessage()); ui->statusLabel->setStyleSheet("QLabel { color : white; font-size: 8pt;}"); - ui->statusButton->setStyleSheet(Style::get(":/ui/statusButton/statusButton.css")); + ui->statusButton->setStyleSheet(Style::getStylesheet(":/ui/statusButton/statusButton.css")); QMenu *statusButtonMenu = new QMenu(ui->statusButton); QAction* setStatusOnline = statusButtonMenu->addAction(Widget::tr("Online","Button to set your status to 'Online'")); From 214e428b7ea8efb6e40b3df5c6ed7fbb924bd611 Mon Sep 17 00:00:00 2001 From: krepa098 Date: Tue, 30 Sep 2014 23:45:33 +0200 Subject: [PATCH 146/205] cleanup, use qss instead of QPalette --- misc/style.cpp | 16 +++++++------- widget/friendwidget.cpp | 21 ------------------- widget/genericchatroomwidget.cpp | 36 +++++++++++++------------------- widget/groupwidget.cpp | 28 ++++++++----------------- 4 files changed, 32 insertions(+), 69 deletions(-) diff --git a/misc/style.cpp b/misc/style.cpp index 0801cf154..84096aad8 100644 --- a/misc/style.cpp +++ b/misc/style.cpp @@ -19,7 +19,14 @@ #include #include -#include + +// helper function +QFont appFont(int pixelSize, int weight) { + auto font = QFont(); + font.setPixelSize(pixelSize); + font.setWeight(weight); + return font; +} QString Style::getStylesheet(const QString &filename) { @@ -51,13 +58,6 @@ QColor Style::getColor(Style::ColorPalette entry) return palette[entry]; } -QFont appFont(int pixelSize, int weight) { - auto font = QFont(); - font.setPixelSize(pixelSize); - font.setWeight(weight); - return font; -} - QFont Style::getFont(Style::Font font) { static QFont fonts[] = { diff --git a/widget/friendwidget.cpp b/widget/friendwidget.cpp index be83930ec..cc4e925de 100644 --- a/widget/friendwidget.cpp +++ b/widget/friendwidget.cpp @@ -35,22 +35,10 @@ FriendWidget::FriendWidget(int FriendId, QString id) : friendId(FriendId) , isDefaultAvatar{true} { - setMouseTracking(true); - setAutoFillBackground(true); - setFixedHeight(55); - setLayout(&layout); - layout.setSpacing(0); - layout.setMargin(0); - layout.setStretchFactor(this, 100); - textLayout.setSpacing(0); - textLayout.setMargin(0); - setLayoutDirection(Qt::LeftToRight); // parent might have set Qt::RightToLeft - avatar = new MaskablePixmapWidget(this, QSize(40,40), ":/img/avatar_mask.png"); avatar->setPixmap(QPixmap(":img/contact.png"), Qt::transparent); name.setText(id); - //statusPic.setAlignment(Qt::AlignHCenter); statusPic.setPixmap(QPixmap(":img/status/dot_away.png")); // status text @@ -65,11 +53,6 @@ FriendWidget::FriendWidget(int FriendId, QString id) name.setPalette(pal2); name.setFont(Style::getFont(Style::Big)); - // background - QPalette pal3; - pal3.setColor(QPalette::Background, Style::getColor(Style::MediumGrey)); - setPalette(pal3); - textLayout.addStretch(); textLayout.addWidget(&name); textLayout.addWidget(&statusMessage); @@ -82,11 +65,7 @@ FriendWidget::FriendWidget(int FriendId, QString id) layout.addSpacing(10); layout.addWidget(&statusPic); layout.addSpacing(10); - - layout.invalidate(); - layout.update(); layout.activate(); - updateGeometry(); } void FriendWidget::contextMenuEvent(QContextMenuEvent * event) diff --git a/widget/genericchatroomwidget.cpp b/widget/genericchatroomwidget.cpp index 224c8f463..971e1c303 100644 --- a/widget/genericchatroomwidget.cpp +++ b/widget/genericchatroomwidget.cpp @@ -22,49 +22,43 @@ GenericChatroomWidget::GenericChatroomWidget(QWidget *parent) : QWidget(parent) , isActiveWidget(false) { + setMouseTracking(true); + setFixedHeight(55); + + setLayout(&layout); + layout.setSpacing(0); + layout.setMargin(0); + textLayout.setSpacing(0); + textLayout.setMargin(0); + setLayoutDirection(Qt::LeftToRight); // parent might have set Qt::RightToLeft + + setStyleSheet(QString("background-color: %1").arg(Style::getColor(Style::MediumGrey).name())); } bool GenericChatroomWidget::isActive() { return isActiveWidget; } - void GenericChatroomWidget::setActive(bool active) { isActiveWidget = active; if (active) - { - QPalette pal; - pal.setColor(QPalette::Background, Style::getColor(Style::White)); - setPalette(pal); - } + setStyleSheet(QString("background-color: %1").arg(Style::getColor(Style::White).name())); else - { - QPalette pal; - pal.setColor(QPalette::Background, Style::getColor(Style::MediumGrey)); - setPalette(pal); - } + setStyleSheet(QString("background-color: %1").arg(Style::getColor(Style::MediumGrey).name())); } void GenericChatroomWidget::leaveEvent(QEvent *) { if (!isActive()) - { - QPalette pal; - pal.setColor(QPalette::Background, Style::getColor(Style::MediumGrey)); - setPalette(pal); - } + setStyleSheet(QString("background-color: %1").arg(Style::getColor(Style::MediumGrey).name())); } void GenericChatroomWidget::enterEvent(QEvent *) { if (!isActive()) - { - QPalette pal; - pal.setColor(QPalette::Background, Style::getColor(Style::MediumGrey).lighter(120)); - setPalette(pal); - } + setStyleSheet(QString("background-color: %1").arg(Style::getColor(Style::MediumGrey).lighter(120).name())); } void GenericChatroomWidget::mouseReleaseEvent(QMouseEvent*) diff --git a/widget/groupwidget.cpp b/widget/groupwidget.cpp index d2af2ba4c..0c24e7183 100644 --- a/widget/groupwidget.cpp +++ b/widget/groupwidget.cpp @@ -30,16 +30,6 @@ GroupWidget::GroupWidget(int GroupId, QString Name) : groupId{GroupId} { - setMouseTracking(true); - setAutoFillBackground(true); - setLayout(&layout); - setFixedHeight(55); - layout.setSpacing(0); - layout.setMargin(0); - textLayout.setSpacing(0); - textLayout.setMargin(0); - setLayoutDirection(Qt::LeftToRight); // parent might have set Qt::RightToLeft - avatar = new MaskablePixmapWidget(this, QSize(40,40), ":/img/avatar_mask.png"); avatar->setPixmap(QPixmap(":img/group.png"), Qt::transparent); @@ -58,11 +48,6 @@ GroupWidget::GroupWidget(int GroupId, QString Name) nusers.setPalette(pal); nusers.setFont(Style::getFont(Style::Medium)); - // background - QPalette pal3; - pal3.setColor(QPalette::Background, Style::getColor(Style::MediumGrey)); - this->setPalette(pal3); - Group* g = GroupList::findGroup(groupId); if (g) nusers.setText(GroupWidget::tr("%1 users in chat").arg(g->peers.size())); @@ -82,6 +67,7 @@ GroupWidget::GroupWidget(int GroupId, QString Name) layout.addSpacing(10); layout.addWidget(&statusPic); layout.addSpacing(10); + layout.activate(); } void GroupWidget::contextMenuEvent(QContextMenuEvent * event) @@ -154,16 +140,20 @@ void GroupWidget::updateStatusLight() { statusPic.setPixmap(QPixmap(":img/status/dot_online.png")); } else { - if (g->userWasMentioned == 0) statusPic.setPixmap(QPixmap(":img/status/dot_online_notification.png")); - else statusPic.setPixmap(QPixmap(":img/status/dot_online_notification.png")); + if (g->userWasMentioned == 0) + statusPic.setPixmap(QPixmap(":img/status/dot_online_notification.png")); + else + statusPic.setPixmap(QPixmap(":img/status/dot_online_notification.png")); } } else { if (g->hasNewMessages == 0) { statusPic.setPixmap(QPixmap(":img/status/dot_groupchat.png")); } else { - if (g->userWasMentioned == 0) statusPic.setPixmap(QPixmap(":img/status/dot_groupchat_newmessages.png")); - else statusPic.setPixmap(QPixmap(":img/status/dot_groupchat_notification.png")); + if (g->userWasMentioned == 0) + statusPic.setPixmap(QPixmap(":img/status/dot_groupchat_newmessages.png")); + else + statusPic.setPixmap(QPixmap(":img/status/dot_groupchat_notification.png")); } } } From 7a292b815eef5ae6ff32f53c72319e39354e1ddb Mon Sep 17 00:00:00 2001 From: krepa098 Date: Wed, 1 Oct 2014 09:58:14 +0200 Subject: [PATCH 147/205] qss vars --- misc/style.cpp | 26 ++++++++++++++++++++++++++ misc/style.h | 3 +++ 2 files changed, 29 insertions(+) diff --git a/misc/style.cpp b/misc/style.cpp index 84096aad8..6b4322e70 100644 --- a/misc/style.cpp +++ b/misc/style.cpp @@ -19,6 +19,8 @@ #include #include +#include +#include // helper function QFont appFont(int pixelSize, int weight) { @@ -51,6 +53,7 @@ QColor Style::getColor(Style::ColorPalette entry) QColor("#000000"), QColor("#1c1c1c"), QColor("#414141"), + QColor("#414141").lighter(120), QColor("#d1d1d1"), QColor("#ffffff"), }; @@ -72,3 +75,26 @@ QFont Style::getFont(Style::Font font) return fonts[font]; } + +QString Style::resolve(QString qss) +{ + static QMap dict = { + {"@green", getColor(Green).name()}, + {"@yellow", getColor(Yellow).name()}, + {"@red", getColor(Red).name()}, + {"@black", getColor(Black).name()}, + {"@darkGrey", getColor(DarkGrey).name()}, + {"@mediumGrey", getColor(MediumGrey).name()}, + {"@mediumGreyLight", getColor(MediumGreyLight).name()}, + {"@lightGrey", getColor(LightGrey).name()}, + {"@white", getColor(White).name()}, + }; + + for (const QString& key : dict.keys()) + { + qDebug() << key; + qss.replace(QRegularExpression(QString("%1\\b").arg(key)), dict[key]); + } + + return qss; +} diff --git a/misc/style.h b/misc/style.h index 326972d92..eba949325 100644 --- a/misc/style.h +++ b/misc/style.h @@ -33,6 +33,7 @@ public: Black, DarkGrey, MediumGrey, + MediumGreyLight, LightGrey, White, }; @@ -51,6 +52,8 @@ public: static QString getStylesheet(const QString& filename); static QColor getColor(ColorPalette entry); static QFont getFont(Font font); + static QString resolve(QString qss); + private: Style(); }; From f7f0f696d8f48ff9a1aac03a2ee875610c9a5625 Mon Sep 17 00:00:00 2001 From: krepa098 Date: Wed, 1 Oct 2014 11:12:02 +0200 Subject: [PATCH 148/205] qss font symbols --- misc/style.cpp | 56 +++++++++++++++++++++++++++++++++++++++++++++----- misc/style.h | 2 ++ 2 files changed, 53 insertions(+), 5 deletions(-) diff --git a/misc/style.cpp b/misc/style.cpp index 6b4322e70..fb8378579 100644 --- a/misc/style.cpp +++ b/misc/style.cpp @@ -21,24 +21,45 @@ #include #include #include +#include +#include -// helper function -QFont appFont(int pixelSize, int weight) { +// helper functions +QFont appFont(int pixelSize, int weight) +{ auto font = QFont(); font.setPixelSize(pixelSize); font.setWeight(weight); return font; } +QString cssifyWeight(int weight) +{ + QString weightStr = "normal"; + if (weight == QFont::Bold) + weightStr = "bold"; + if (weight == QFont::Light) + weightStr = "lighter"; + + return QString("%1").arg(weightStr); +} + +QString cssifyFont(QFont font) +{ + return QString("%1px %2") + .arg(font.pixelSize()) + .arg(font.weight()); +} + QString Style::getStylesheet(const QString &filename) { if (!Settings::getInstance().getUseNativeStyle()) { QFile file(filename); if (file.open(QFile::ReadOnly | QFile::Text)) - return file.readAll(); + return resolve(file.readAll()); else - qWarning() << "Stylesheet " << filename << " not found"; + qWarning() << "Style: Stylesheet " << filename << " not found"; } return QString(); @@ -79,6 +100,7 @@ QFont Style::getFont(Style::Font font) QString Style::resolve(QString qss) { static QMap dict = { + // colors {"@green", getColor(Green).name()}, {"@yellow", getColor(Yellow).name()}, {"@red", getColor(Red).name()}, @@ -88,13 +110,37 @@ QString Style::resolve(QString qss) {"@mediumGreyLight", getColor(MediumGreyLight).name()}, {"@lightGrey", getColor(LightGrey).name()}, {"@white", getColor(White).name()}, + + // fonts + {"@extraBig", cssifyFont(getFont(ExtraBig))}, + {"@big", cssifyFont(getFont(Big))}, + {"@bigBold", cssifyFont(getFont(BigBold))}, + {"@medium", cssifyFont(getFont(Medium))}, + {"@mediumBold", cssifyFont(getFont(MediumBold))}, + {"@small", cssifyFont(getFont(Small))}, + {"@smallLight", cssifyFont(getFont(SmallLight))}, }; for (const QString& key : dict.keys()) { - qDebug() << key; qss.replace(QRegularExpression(QString("%1\\b").arg(key)), dict[key]); } return qss; } + +void Style::repolish(QWidget *w) +{ + w->style()->unpolish(w); + w->style()->polish(w); + + for (QObject* o : w->children()) + { + QWidget* c = qobject_cast(o); + if (c) + { + c->style()->unpolish(c); + c->style()->polish(c); + } + } +} diff --git a/misc/style.h b/misc/style.h index eba949325..35c0b7e98 100644 --- a/misc/style.h +++ b/misc/style.h @@ -21,6 +21,7 @@ #include class QString; +class QWidget; class Style { @@ -53,6 +54,7 @@ public: static QColor getColor(ColorPalette entry); static QFont getFont(Font font); static QString resolve(QString qss); + static void repolish(QWidget* w); private: Style(); From 04f56cc9ec16bda63d13ab1c5c67b041ac21bc9e Mon Sep 17 00:00:00 2001 From: krepa098 Date: Wed, 1 Oct 2014 11:13:49 +0200 Subject: [PATCH 149/205] unmessification --- friend.cpp | 8 ++-- res.qrc | 1 + widget/form/chatform.cpp | 1 + widget/form/groupchatform.cpp | 2 +- widget/friendwidget.cpp | 54 ++------------------------- widget/friendwidget.h | 4 -- widget/genericchatroomwidget.cpp | 64 ++++++++++++++++++++++++-------- widget/genericchatroomwidget.h | 18 ++++++--- widget/groupwidget.cpp | 61 +++--------------------------- widget/groupwidget.h | 4 -- 10 files changed, 75 insertions(+), 142 deletions(-) diff --git a/friend.cpp b/friend.cpp index 6676cea81..5f48197dd 100644 --- a/friend.cpp +++ b/friend.cpp @@ -36,19 +36,17 @@ Friend::~Friend() void Friend::setName(QString name) { - widget->name.setText(name); - widget->name.setToolTip(name); // for overlength names + widget->setName(name); chatForm->setName(name); } void Friend::setStatusMessage(QString message) { - widget->statusMessage.setText(message); - widget->statusMessage.setToolTip(message); // for overlength messsages + widget->setStatusMsg(message); chatForm->setStatusMessage(message); } QString Friend::getName() { - return widget->name.text(); + return widget->getName(); } diff --git a/res.qrc b/res.qrc index c4719df01..5b4910039 100644 --- a/res.qrc +++ b/res.qrc @@ -145,5 +145,6 @@ translations/uk.qm img/avatar_mask.png img/group_2x.png + ui/chatroomWidgets/genericChatroomWidget.css diff --git a/widget/form/chatform.cpp b/widget/form/chatform.cpp index 8697da744..efe61f818 100644 --- a/widget/form/chatform.cpp +++ b/widget/form/chatform.cpp @@ -34,6 +34,7 @@ #include "core.h" #include "widget/widget.h" #include "widget/maskablepixmapwidget.h" +#include "widget/croppinglabel.h" #include "style.h" ChatForm::ChatForm(Friend* chatFriend) diff --git a/widget/form/groupchatform.cpp b/widget/form/groupchatform.cpp index 5c3253afe..77e64ea83 100644 --- a/widget/form/groupchatform.cpp +++ b/widget/form/groupchatform.cpp @@ -41,7 +41,7 @@ GroupChatForm::GroupChatForm(Group* chatGroup) QFont small; small.setPixelSize(10); - nameLabel->setText(group->widget->name.text()); + nameLabel->setText(group->widget->getName()); nusersLabel->setFont(Style::getFont(Style::Medium)); nusersLabel->setText(GroupChatForm::tr("%1 users in chat","Number of users in chat").arg(group->peers.size())); diff --git a/widget/friendwidget.cpp b/widget/friendwidget.cpp index cc4e925de..9159d3e7f 100644 --- a/widget/friendwidget.cpp +++ b/widget/friendwidget.cpp @@ -23,6 +23,7 @@ #include "core.h" #include "widget/form/chatform.h" #include "widget/maskablepixmapwidget.h" +#include "widget/croppinglabel.h" #include "style.h" #include #include @@ -35,37 +36,9 @@ FriendWidget::FriendWidget(int FriendId, QString id) : friendId(FriendId) , isDefaultAvatar{true} { - avatar = new MaskablePixmapWidget(this, QSize(40,40), ":/img/avatar_mask.png"); avatar->setPixmap(QPixmap(":img/contact.png"), Qt::transparent); - - name.setText(id); statusPic.setPixmap(QPixmap(":img/status/dot_away.png")); - - // status text - QPalette pal; - pal.setColor(QPalette::WindowText, Style::getColor(Style::LightGrey)); - statusMessage.setPalette(pal); - statusMessage.setFont(Style::getFont(Style::Medium)); - - // name text - QPalette pal2; - pal2.setColor(QPalette::WindowText, Style::getColor(Style::White)); - name.setPalette(pal2); - name.setFont(Style::getFont(Style::Big)); - - textLayout.addStretch(); - textLayout.addWidget(&name); - textLayout.addWidget(&statusMessage); - textLayout.addStretch(); - - layout.addSpacing(20); - layout.addWidget(avatar); - layout.addSpacing(10); - layout.addLayout(&textLayout); - layout.addSpacing(10); - layout.addWidget(&statusPic); - layout.addSpacing(10); - layout.activate(); + nameLabel->setText(id); } void FriendWidget::contextMenuEvent(QContextMenuEvent * event) @@ -77,7 +50,7 @@ void FriendWidget::contextMenuEvent(QContextMenuEvent * event) QMap groupActions; for (Group* group : GroupList::groupList) { - QAction* groupAction = inviteMenu->addAction(group->widget->name.text()); + QAction* groupAction = inviteMenu->addAction(group->widget->getName()); groupActions[groupAction] = group; } if (groupActions.isEmpty()) @@ -113,16 +86,6 @@ void FriendWidget::setAsActiveChatroom() { setActive(true); - // status - QPalette pal; - pal.setColor(QPalette::WindowText, Style::getColor(Style::MediumGrey)); - statusMessage.setPalette(pal); - - // name - QPalette pal2; - pal2.setColor(QPalette::WindowText, Style::getColor(Style::DarkGrey)); - name.setPalette(pal2); - if (isDefaultAvatar) avatar->setPixmap(QPixmap(":img/contact_dark.png"), Qt::transparent); } @@ -131,17 +94,6 @@ void FriendWidget::setAsInactiveChatroom() { setActive(false); - // status - QPalette pal; - pal.setColor(QPalette::WindowText, Style::getColor(Style::LightGrey)); - statusMessage.setPalette(pal); - - // name - QPalette pal2; - pal2.setColor(QPalette::WindowText, Style::getColor(Style::White)); - name.setPalette(pal2); - QPalette pal3; - if (isDefaultAvatar) avatar->setPixmap(QPixmap(":img/contact.png"), Qt::transparent); } diff --git a/widget/friendwidget.h b/widget/friendwidget.h index cc29c0385..a04a5e76e 100644 --- a/widget/friendwidget.h +++ b/widget/friendwidget.h @@ -20,7 +20,6 @@ #include #include "genericchatroomwidget.h" -#include "croppinglabel.h" class QPixmap; class MaskablePixmapWidget; @@ -52,9 +51,6 @@ protected: public: int friendId; - MaskablePixmapWidget* avatar; - QLabel statusPic; - CroppingLabel name, statusMessage; bool isDefaultAvatar; QPoint dragStartPos; }; diff --git a/widget/genericchatroomwidget.cpp b/widget/genericchatroomwidget.cpp index 971e1c303..ab0d13810 100644 --- a/widget/genericchatroomwidget.cpp +++ b/widget/genericchatroomwidget.cpp @@ -16,13 +16,14 @@ #include "genericchatroomwidget.h" #include "style.h" +#include "widget/maskablepixmapwidget.h" +#include "croppinglabel.h" #include +#include GenericChatroomWidget::GenericChatroomWidget(QWidget *parent) : QWidget(parent) - , isActiveWidget(false) { - setMouseTracking(true); setFixedHeight(55); setLayout(&layout); @@ -32,33 +33,64 @@ GenericChatroomWidget::GenericChatroomWidget(QWidget *parent) textLayout.setMargin(0); setLayoutDirection(Qt::LeftToRight); // parent might have set Qt::RightToLeft - setStyleSheet(QString("background-color: %1").arg(Style::getColor(Style::MediumGrey).name())); + // avatar + avatar = new MaskablePixmapWidget(this, QSize(40,40), ":/img/avatar_mask.png"); + + // status text + statusMessageLabel = new CroppingLabel(this); + statusMessageLabel->setObjectName("status"); + + // name text + nameLabel = new CroppingLabel(this); + nameLabel->setObjectName("name"); + + textLayout.addStretch(); + textLayout.addWidget(nameLabel); + textLayout.addWidget(statusMessageLabel); + textLayout.addStretch(); + + layout.addSpacing(20); + layout.addWidget(avatar); + layout.addSpacing(10); + layout.addLayout(&textLayout); + layout.addSpacing(10); + layout.addWidget(&statusPic); + layout.addSpacing(10); + layout.activate(); + + setProperty("active", false); + setStyleSheet(Style::getStylesheet(":/ui/chatroomWidgets/genericChatroomWidget.css")); } bool GenericChatroomWidget::isActive() { - return isActiveWidget; + return property("active").toBool(); } + void GenericChatroomWidget::setActive(bool active) { - isActiveWidget = active; - - if (active) - setStyleSheet(QString("background-color: %1").arg(Style::getColor(Style::White).name())); - else - setStyleSheet(QString("background-color: %1").arg(Style::getColor(Style::MediumGrey).name())); + setProperty("active", active); + Style::repolish(this); } -void GenericChatroomWidget::leaveEvent(QEvent *) +void GenericChatroomWidget::setName(const QString &name) { - if (!isActive()) - setStyleSheet(QString("background-color: %1").arg(Style::getColor(Style::MediumGrey).name())); + nameLabel->setText(name); } -void GenericChatroomWidget::enterEvent(QEvent *) +void GenericChatroomWidget::setStatusMsg(const QString &status) { - if (!isActive()) - setStyleSheet(QString("background-color: %1").arg(Style::getColor(Style::MediumGrey).lighter(120).name())); + statusMessageLabel->setText(status); +} + +QString GenericChatroomWidget::getName() const +{ + return nameLabel->text(); +} + +QString GenericChatroomWidget::getStatusMsg() const +{ + return statusMessageLabel->text(); } void GenericChatroomWidget::mouseReleaseEvent(QMouseEvent*) diff --git a/widget/genericchatroomwidget.h b/widget/genericchatroomwidget.h index 84b1f2669..a6e001e4b 100644 --- a/widget/genericchatroomwidget.h +++ b/widget/genericchatroomwidget.h @@ -20,6 +20,10 @@ #include #include #include +#include + +class CroppingLabel; +class MaskablePixmapWidget; namespace Ui { class MainWindow; @@ -31,8 +35,6 @@ class GenericChatroomWidget : public QWidget public: GenericChatroomWidget(QWidget *parent = 0); void mouseReleaseEvent (QMouseEvent* event); - void leaveEvent(QEvent *); - void enterEvent(QEvent *); virtual void setAsActiveChatroom(){;} virtual void setAsInactiveChatroom(){;} @@ -43,18 +45,24 @@ public: bool isActive(); void setActive(bool active); + void setName(const QString& name); + void setStatusMsg(const QString& status); + + QString getName() const; + QString getStatusMsg() const; + signals: void chatroomWidgetClicked(GenericChatroomWidget* widget); public slots: -private: - bool isActiveWidget; - protected: QColor lastColor; QHBoxLayout layout; QVBoxLayout textLayout; + MaskablePixmapWidget* avatar; + QLabel statusPic; + CroppingLabel *nameLabel, *statusMessageLabel; }; #endif // GENERICCHATROOMWIDGET_H diff --git a/widget/groupwidget.cpp b/widget/groupwidget.cpp index 0c24e7183..2d7b1ebe5 100644 --- a/widget/groupwidget.cpp +++ b/widget/groupwidget.cpp @@ -30,44 +30,15 @@ GroupWidget::GroupWidget(int GroupId, QString Name) : groupId{GroupId} { - avatar = new MaskablePixmapWidget(this, QSize(40,40), ":/img/avatar_mask.png"); avatar->setPixmap(QPixmap(":img/group.png"), Qt::transparent); - statusPic.setPixmap(QPixmap(":img/status/dot_online.png")); - - // name - QPalette pal2; - pal2.setColor(QPalette::WindowText, Style::getColor(Style::White)); - name.setPalette(pal2); - name.setText(Name); - name.setFont(Style::getFont(Style::Big)); - - // status - QPalette pal; - pal.setColor(QPalette::WindowText, Style::getColor(Style::LightGrey)); - nusers.setPalette(pal); - nusers.setFont(Style::getFont(Style::Medium)); + nameLabel->setText(Name); Group* g = GroupList::findGroup(groupId); if (g) - nusers.setText(GroupWidget::tr("%1 users in chat").arg(g->peers.size())); + statusMessageLabel->setText(GroupWidget::tr("%1 users in chat").arg(g->peers.size())); else - nusers.setText(GroupWidget::tr("0 users in chat")); - - textLayout.addStretch(); - textLayout.addWidget(&name); - textLayout.addWidget(&nusers); - textLayout.addStretch(); - - layout.addSpacing(20); - layout.addWidget(avatar); - layout.addSpacing(10); - layout.addLayout(&textLayout); - layout.addStretch(); - layout.addSpacing(10); - layout.addWidget(&statusPic); - layout.addSpacing(10); - layout.activate(); + statusMessageLabel->setText(GroupWidget::tr("0 users in chat")); } void GroupWidget::contextMenuEvent(QContextMenuEvent * event) @@ -91,42 +62,20 @@ void GroupWidget::onUserListChanged() { Group* g = GroupList::findGroup(groupId); if (g) - nusers.setText(tr("%1 users in chat").arg(g->nPeers)); + statusMessageLabel->setText(tr("%1 users in chat").arg(g->nPeers)); else - nusers.setText(tr("0 users in chat")); + statusMessageLabel->setText(tr("0 users in chat")); } void GroupWidget::setAsActiveChatroom() { setActive(true); - - // status - QPalette pal; - pal.setColor(QPalette::WindowText, Style::getColor(Style::MediumGrey)); - nusers.setPalette(pal); - - // name - QPalette pal2; - pal2.setColor(QPalette::WindowText, Style::getColor(Style::DarkGrey)); - name.setPalette(pal2); - avatar->setPixmap(QPixmap(":img/group_dark.png"), Qt::transparent); } void GroupWidget::setAsInactiveChatroom() { setActive(false); - - // status - QPalette pal; - pal.setColor(QPalette::WindowText, Style::getColor(Style::LightGrey)); - nusers.setPalette(pal); - - // name - QPalette pal2; - pal2.setColor(QPalette::WindowText, Style::getColor(Style::White)); - name.setPalette(pal2); - avatar->setPixmap(QPixmap(":img/group.png"), Qt::transparent); } diff --git a/widget/groupwidget.h b/widget/groupwidget.h index 960ab9cb7..2d35000a0 100644 --- a/widget/groupwidget.h +++ b/widget/groupwidget.h @@ -20,8 +20,6 @@ #include #include "genericchatroomwidget.h" -class MaskablePixmapWidget; - class GroupWidget : public GenericChatroomWidget { Q_OBJECT @@ -41,8 +39,6 @@ signals: public: int groupId; - QLabel name, nusers, statusPic; - MaskablePixmapWidget* avatar; }; #endif // GROUPWIDGET_H From 5e328d24048788121fa177abd1a52bcde7c925f0 Mon Sep 17 00:00:00 2001 From: krepa098 Date: Wed, 1 Oct 2014 16:17:09 +0200 Subject: [PATCH 150/205] more styling --- misc/style.cpp | 27 +++++----- ui/chatArea/innerStyle.css | 56 +++++++++++--------- ui/chatroomWidgets/genericChatroomWidget.css | 38 +++++++++++++ ui/emoticonWidget/emoticonWidget.css | 2 +- ui/msgEdit/msgEdit.css | 2 +- widget/chatareawidget.cpp | 25 +++++---- widget/form/chatform.cpp | 2 +- widget/form/groupchatform.cpp | 2 +- widget/friendwidget.cpp | 2 +- widget/genericchatroomwidget.cpp | 2 +- widget/groupwidget.cpp | 2 +- widget/tool/chatactions/chataction.cpp | 10 ++-- widget/tool/chatactions/messageaction.cpp | 5 +- 13 files changed, 114 insertions(+), 61 deletions(-) create mode 100644 ui/chatroomWidgets/genericChatroomWidget.css diff --git a/misc/style.cpp b/misc/style.cpp index fb8378579..b4d1cc209 100644 --- a/misc/style.cpp +++ b/misc/style.cpp @@ -27,28 +27,29 @@ // helper functions QFont appFont(int pixelSize, int weight) { - auto font = QFont(); + QFont font; font.setPixelSize(pixelSize); font.setWeight(weight); return font; } -QString cssifyWeight(int weight) +QString qssifyWeight(int weight) { QString weightStr = "normal"; if (weight == QFont::Bold) weightStr = "bold"; if (weight == QFont::Light) - weightStr = "lighter"; + weightStr = "light"; return QString("%1").arg(weightStr); } -QString cssifyFont(QFont font) +QString qssifyFont(QFont font) { - return QString("%1px %2") + return QString("%1px %2 \"%3\"") .arg(font.pixelSize()) - .arg(font.weight()); + .arg(qssifyWeight(font.weight())) + .arg(font.family()); } QString Style::getStylesheet(const QString &filename) @@ -112,13 +113,13 @@ QString Style::resolve(QString qss) {"@white", getColor(White).name()}, // fonts - {"@extraBig", cssifyFont(getFont(ExtraBig))}, - {"@big", cssifyFont(getFont(Big))}, - {"@bigBold", cssifyFont(getFont(BigBold))}, - {"@medium", cssifyFont(getFont(Medium))}, - {"@mediumBold", cssifyFont(getFont(MediumBold))}, - {"@small", cssifyFont(getFont(Small))}, - {"@smallLight", cssifyFont(getFont(SmallLight))}, + {"@extraBig", qssifyFont(getFont(ExtraBig))}, + {"@big", qssifyFont(getFont(Big))}, + {"@bigBold", qssifyFont(getFont(BigBold))}, + {"@medium", qssifyFont(getFont(Medium))}, + {"@mediumBold", qssifyFont(getFont(MediumBold))}, + {"@small", qssifyFont(getFont(Small))}, + {"@smallLight", qssifyFont(getFont(SmallLight))}, }; for (const QString& key : dict.keys()) diff --git a/ui/chatArea/innerStyle.css b/ui/chatArea/innerStyle.css index 28bcb32c8..fd0ca03ee 100644 --- a/ui/chatArea/innerStyle.css +++ b/ui/chatArea/innerStyle.css @@ -1,25 +1,31 @@ -div.name_me { - color: #646464; - font-weight: bold; - padding-right: 3px; -} - div.name { - color: #000000; - font-weight: bold; - padding-right: 3px; + color: @black; + font: @big; } div.message { - color: #000000; - padding-right: 3px; - padding-left: 3px; + color: @black; + font: @big; } div.date { - color: #000000; - padding-left: 3px; - white-space: nowrap; + color: @black; + font: @big; +} + +div.name_me { + color: @mediumGrey; + font: @big; +} + +div.message_me { + color: @mediumGrey; + font: @big; +} + +div.date_me { + color: @mediumGrey; + font: @big; } span.quote { @@ -31,9 +37,9 @@ div.green { margin-bottom: 12px; margin-left: 12px; margin-right: 12px; - color: #ffffff; - background-color: #6bc260; - font-size: 10px; + color: @white; + background-color: @green; + font: @small; } div.silver { @@ -41,9 +47,9 @@ div.silver { margin-bottom: 12px; margin-left: 12px; margin-right: 12px; - color: #000000; - background-color: #d1d1d1; - font-size: 10px; + color: @black; + background-color: @lightGrey; + font: @small; } div.red { @@ -51,14 +57,14 @@ div.red { margin-bottom: 12px; margin-left: 12px; margin-right: 12px; - color: #ffffff; - background-color: rgb(200,78,78); - font-size: 10px; + color: @white; + background-color: @red; + font: @small; } div.button { margin-top: 0px; margin-bottom: 0px; margin-left: 0px; - color: #ffffff; + color: @white; } diff --git a/ui/chatroomWidgets/genericChatroomWidget.css b/ui/chatroomWidgets/genericChatroomWidget.css new file mode 100644 index 000000000..4ed573fb0 --- /dev/null +++ b/ui/chatroomWidgets/genericChatroomWidget.css @@ -0,0 +1,38 @@ +GenericChatroomWidget +{ + background-color: @mediumGrey; +} + +GenericChatroomWidget[active="true"] +{ + background-color: @white; +} + +GenericChatroomWidget[active="false"]:hover +{ + background-color: @mediumGreyLight; +} + +GenericChatroomWidget[active="true"] > QLabel#status +{ + font: @medium; + color: @mediumGrey; +} + +GenericChatroomWidget[active="false"] > QLabel#status +{ + font: @medium; + color: @lightGrey; +} + +GenericChatroomWidget[active="true"] > QLabel#name +{ + font: @big; + color: @darkGrey; +} + +GenericChatroomWidget[active="false"] > QLabel#name +{ + font: @big; + color: @white; +} \ No newline at end of file diff --git a/ui/emoticonWidget/emoticonWidget.css b/ui/emoticonWidget/emoticonWidget.css index eb168a07e..093db5122 100644 --- a/ui/emoticonWidget/emoticonWidget.css +++ b/ui/emoticonWidget/emoticonWidget.css @@ -35,6 +35,6 @@ QRadioButton::indicator::checked QMenu { - background-color: #414141; /* sets background of the menu */ + background-color: @mediumGrey; /* sets background of the menu */ border: 0px solid; } diff --git a/ui/msgEdit/msgEdit.css b/ui/msgEdit/msgEdit.css index 2509f57fc..bbc967ccc 100644 --- a/ui/msgEdit/msgEdit.css +++ b/ui/msgEdit/msgEdit.css @@ -1,5 +1,5 @@ QTextEdit { - border-color: #c4c1bd; + border-color: @lightGrey; border-style: solid; border-width: 1px 0 1px 1px; } diff --git a/widget/chatareawidget.cpp b/widget/chatareawidget.cpp index c2e7a90b6..a2c1d6384 100644 --- a/widget/chatareawidget.cpp +++ b/widget/chatareawidget.cpp @@ -36,19 +36,20 @@ ChatAreaWidget::ChatAreaWidget(QWidget *parent) : setAcceptRichText(false); setFrameStyle(QFrame::NoFrame); - chatTextTable = textCursor().insertTable(1,3); - QTextTableFormat tableFormat; + tableFormat.setCellSpacing(15); tableFormat.setBorderStyle(QTextFrameFormat::BorderStyle_None); - tableFormat.setCellSpacing(2); - tableFormat.setWidth(QTextLength(QTextLength::PercentageLength,100)); - chatTextTable->setFormat(tableFormat); - setNameColWidth(100); + tableFormat.setColumnWidthConstraints({QTextLength(QTextLength::VariableLength,0), + QTextLength(QTextLength::PercentageLength,100), + QTextLength(QTextLength::VariableLength,0)}); + + chatTextTable = textCursor().insertTable(1,3,tableFormat); + + nameFormat.setAlignment(Qt::AlignRight); + nameFormat.setNonBreakableLines(true); + dateFormat.setAlignment(Qt::AlignLeft); + dateFormat.setNonBreakableLines(true); -// nameFormat.setAlignment(Qt::AlignRight); -// nameFormat.setNonBreakableLines(true); -// dateFormat.setAlignment(Qt::AlignLeft); -// dateFormat.setNonBreakableLines(true); connect(this, &ChatAreaWidget::anchorClicked, this, &ChatAreaWidget::onAnchorClicked); connect(verticalScrollBar(), SIGNAL(rangeChanged(int,int)), this, SLOT(onSliderRangeChanged())); @@ -112,9 +113,11 @@ void ChatAreaWidget::insertMessage(ChatAction *msgAction) cur.clearSelection(); cur.setKeepPositionOnInsert(true); chatTextTable->appendRows(1); + chatTextTable->cellAt(row,0).firstCursorPosition().setBlockFormat(nameFormat); chatTextTable->cellAt(row,0).firstCursorPosition().insertHtml(msgAction->getName()); chatTextTable->cellAt(row,1).firstCursorPosition().insertHtml(msgAction->getMessage()); - chatTextTable->cellAt(row,2).firstCursorPosition().insertText(msgAction->getDate()); + chatTextTable->cellAt(row,2).firstCursorPosition().setBlockFormat(dateFormat); + chatTextTable->cellAt(row,2).firstCursorPosition().insertHtml(msgAction->getDate()); msgAction->setup(cur, this); diff --git a/widget/form/chatform.cpp b/widget/form/chatform.cpp index efe61f818..f2f2c32d6 100644 --- a/widget/form/chatform.cpp +++ b/widget/form/chatform.cpp @@ -35,7 +35,7 @@ #include "widget/widget.h" #include "widget/maskablepixmapwidget.h" #include "widget/croppinglabel.h" -#include "style.h" +#include "misc/style.h" ChatForm::ChatForm(Friend* chatFriend) : f(chatFriend) diff --git a/widget/form/groupchatform.cpp b/widget/form/groupchatform.cpp index 77e64ea83..412ef46e8 100644 --- a/widget/form/groupchatform.cpp +++ b/widget/form/groupchatform.cpp @@ -21,7 +21,7 @@ #include "widget/croppinglabel.h" #include "widget/maskablepixmapwidget.h" #include "core.h" -#include "style.h" +#include "misc/style.h" #include #include #include diff --git a/widget/friendwidget.cpp b/widget/friendwidget.cpp index 9159d3e7f..a524a7daf 100644 --- a/widget/friendwidget.cpp +++ b/widget/friendwidget.cpp @@ -24,7 +24,7 @@ #include "widget/form/chatform.h" #include "widget/maskablepixmapwidget.h" #include "widget/croppinglabel.h" -#include "style.h" +#include "misc/style.h" #include #include #include diff --git a/widget/genericchatroomwidget.cpp b/widget/genericchatroomwidget.cpp index ab0d13810..cd75964d8 100644 --- a/widget/genericchatroomwidget.cpp +++ b/widget/genericchatroomwidget.cpp @@ -15,7 +15,7 @@ */ #include "genericchatroomwidget.h" -#include "style.h" +#include "misc/style.h" #include "widget/maskablepixmapwidget.h" #include "croppinglabel.h" #include diff --git a/widget/groupwidget.cpp b/widget/groupwidget.cpp index 2d7b1ebe5..aeecb3737 100644 --- a/widget/groupwidget.cpp +++ b/widget/groupwidget.cpp @@ -20,7 +20,7 @@ #include "misc/settings.h" #include "widget/form/groupchatform.h" #include "widget/maskablepixmapwidget.h" -#include "style.h" +#include "misc/style.h" #include #include #include diff --git a/widget/tool/chatactions/chataction.cpp b/widget/tool/chatactions/chataction.cpp index 7758aae33..6978711a6 100644 --- a/widget/tool/chatactions/chataction.cpp +++ b/widget/tool/chatactions/chataction.cpp @@ -41,13 +41,15 @@ QString ChatAction::QImage2base64(const QImage &img) QString ChatAction::getName() { if (isMe) - return QString("
" + toHtmlChars(name) + "
"); + return QString("
%2
").arg("name_me").arg(toHtmlChars(name)); else - return QString("
" + toHtmlChars(name) + "
"); + return QString("
%2
").arg("name").arg(toHtmlChars(name)); } QString ChatAction::getDate() { - QString res = date; - return res; + if (isMe) + return QString("
" + toHtmlChars(date) + "
"); + else + return QString("
" + toHtmlChars(date) + "
"); } diff --git a/widget/tool/chatactions/messageaction.cpp b/widget/tool/chatactions/messageaction.cpp index 9904be470..6445279ea 100644 --- a/widget/tool/chatactions/messageaction.cpp +++ b/widget/tool/chatactions/messageaction.cpp @@ -71,5 +71,8 @@ QString MessageAction::getMessage() } message_ = message_.left(message_.length()-4); - return QString("
" + message_ + "
"); + if (isMe) + return QString("
" + message_ + "
"); + else + return QString("
" + message_ + "
"); } From a159b808012d25a19e4f1507b748a148caaeb21f Mon Sep 17 00:00:00 2001 From: krepa098 Date: Wed, 1 Oct 2014 16:31:23 +0200 Subject: [PATCH 151/205] removed workaround --- widget/groupwidget.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/widget/groupwidget.cpp b/widget/groupwidget.cpp index aeecb3737..ab64a54da 100644 --- a/widget/groupwidget.cpp +++ b/widget/groupwidget.cpp @@ -49,13 +49,7 @@ void GroupWidget::contextMenuEvent(QContextMenuEvent * event) QAction* selectedItem = menu.exec(pos); if (selectedItem == quitGroup) - { - hide(); - show(); //Toggle visibility to work around bug of repaintEvent() not being fired on parent widget when this is hidden - hide(); emit removeGroup(groupId); - return; - } } void GroupWidget::onUserListChanged() From ff8abd50166277f1aa5a1f01854e581c90f33833 Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Wed, 1 Oct 2014 16:49:54 +0200 Subject: [PATCH 152/205] Fix #361, load Qt runtime platform plugins --- main.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/main.cpp b/main.cpp index 8e981baa5..e21c1c647 100644 --- a/main.cpp +++ b/main.cpp @@ -27,6 +27,10 @@ int main(int argc, char *argv[]) a.setApplicationName("qTox"); a.setOrganizationName("Tox"); + // Windows platform plugins DLL hell fix + QCoreApplication::addLibraryPath(QCoreApplication::applicationDirPath()); + a.addLibraryPath("platforms"); + // Load translations QTranslator translator; if (Settings::getInstance().getUseTranslations()) From 8db22973e92586afb646412f9eb5b10928bf9e35 Mon Sep 17 00:00:00 2001 From: krepa098 Date: Wed, 1 Oct 2014 17:03:59 +0200 Subject: [PATCH 153/205] fixed merge --- widget/chatareawidget.cpp | 8 ++++---- widget/form/genericchatform.cpp | 4 +++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/widget/chatareawidget.cpp b/widget/chatareawidget.cpp index a2c1d6384..c743574fa 100644 --- a/widget/chatareawidget.cpp +++ b/widget/chatareawidget.cpp @@ -23,8 +23,9 @@ #include #include -ChatAreaWidget::ChatAreaWidget(QWidget *parent) : - QTextBrowser(parent) +ChatAreaWidget::ChatAreaWidget(QWidget *parent) + : QTextBrowser(parent) + , nameWidth(75) { setReadOnly(true); viewport()->setCursor(Qt::ArrowCursor); @@ -39,7 +40,7 @@ ChatAreaWidget::ChatAreaWidget(QWidget *parent) : QTextTableFormat tableFormat; tableFormat.setCellSpacing(15); tableFormat.setBorderStyle(QTextFrameFormat::BorderStyle_None); - tableFormat.setColumnWidthConstraints({QTextLength(QTextLength::VariableLength,0), + tableFormat.setColumnWidthConstraints({QTextLength(QTextLength::FixedLength,nameWidth), QTextLength(QTextLength::PercentageLength,100), QTextLength(QTextLength::VariableLength,0)}); @@ -50,7 +51,6 @@ ChatAreaWidget::ChatAreaWidget(QWidget *parent) : dateFormat.setAlignment(Qt::AlignLeft); dateFormat.setNonBreakableLines(true); - connect(this, &ChatAreaWidget::anchorClicked, this, &ChatAreaWidget::onAnchorClicked); connect(verticalScrollBar(), SIGNAL(rangeChanged(int,int)), this, SLOT(onSliderRangeChanged())); } diff --git a/widget/form/genericchatform.cpp b/widget/form/genericchatform.cpp index 2abdd0def..a7bcb5e2b 100644 --- a/widget/form/genericchatform.cpp +++ b/widget/form/genericchatform.cpp @@ -173,7 +173,9 @@ void GenericChatForm::addMessage(QString author, QString message, QDateTime date if (previousName == author) chatWidget->insertMessage(new MessageAction("", message, date, isMe)); - else chatWidget->insertMessage(new MessageAction(getElidedName(author) , message, date, isMe)); + else + chatWidget->insertMessage(new MessageAction(getElidedName(author) , message, date, isMe)); + previousName = author; } From e0e20d3ae7aef6a646c94d274c0f30a3b193d7d9 Mon Sep 17 00:00:00 2001 From: krepa098 Date: Wed, 1 Oct 2014 17:22:51 +0200 Subject: [PATCH 154/205] AdjustingScrollArea: removed event filter --- widget/adjustingscrollarea.cpp | 14 -------------- widget/adjustingscrollarea.h | 1 - 2 files changed, 15 deletions(-) diff --git a/widget/adjustingscrollarea.cpp b/widget/adjustingscrollarea.cpp index 04b735ed1..29315ba8b 100644 --- a/widget/adjustingscrollarea.cpp +++ b/widget/adjustingscrollarea.cpp @@ -48,17 +48,3 @@ QSize AdjustingScrollArea::sizeHint() const return QScrollArea::sizeHint(); } - -bool AdjustingScrollArea::eventFilter(QObject *obj, QEvent *ev) -{ - if (ev->type() == QEvent::Paint) - { - // workaround: sometimes a child widget gets drawn on top of the scrollbar - // so we trigger a repaint afterwards - // => Actually, we don't. This triggers an infinite loop of QEvent::UpdateRequest and burns 100% CPU ! - //verticalScrollBar()->update(); - //horizontalScrollBar()->update(); - } - - return QObject::eventFilter(obj, ev); -} diff --git a/widget/adjustingscrollarea.h b/widget/adjustingscrollarea.h index 380ac5df8..584e4e875 100644 --- a/widget/adjustingscrollarea.h +++ b/widget/adjustingscrollarea.h @@ -27,7 +27,6 @@ public: virtual void resizeEvent(QResizeEvent *ev) override; virtual QSize sizeHint() const override; - virtual bool eventFilter(QObject *obj, QEvent *ev) override; }; #endif // ADJUSTINGSCROLLAREA_H From f99825580a483f00d36f063acca2e0dafb1f9b31 Mon Sep 17 00:00:00 2001 From: krepa098 Date: Wed, 1 Oct 2014 18:20:13 +0200 Subject: [PATCH 155/205] AutoFillBackground --- widget/genericchatroomwidget.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/widget/genericchatroomwidget.cpp b/widget/genericchatroomwidget.cpp index cd75964d8..d346828b2 100644 --- a/widget/genericchatroomwidget.cpp +++ b/widget/genericchatroomwidget.cpp @@ -25,6 +25,7 @@ GenericChatroomWidget::GenericChatroomWidget(QWidget *parent) : QWidget(parent) { setFixedHeight(55); + setAutoFillBackground(true); setLayout(&layout); layout.setSpacing(0); From 226c0f2cf186e332a63e1e2e88052cc3ef528812 Mon Sep 17 00:00:00 2001 From: krepa098 Date: Wed, 1 Oct 2014 18:53:31 +0200 Subject: [PATCH 156/205] GenericChatroomWidget: use QFrame instead of QWidget as base class (fixes invisible background) --- widget/genericchatroomwidget.cpp | 3 +-- widget/genericchatroomwidget.h | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/widget/genericchatroomwidget.cpp b/widget/genericchatroomwidget.cpp index d346828b2..8e875bd3e 100644 --- a/widget/genericchatroomwidget.cpp +++ b/widget/genericchatroomwidget.cpp @@ -22,10 +22,9 @@ #include GenericChatroomWidget::GenericChatroomWidget(QWidget *parent) - : QWidget(parent) + : QFrame(parent) { setFixedHeight(55); - setAutoFillBackground(true); setLayout(&layout); layout.setSpacing(0); diff --git a/widget/genericchatroomwidget.h b/widget/genericchatroomwidget.h index a6e001e4b..1dd6d8250 100644 --- a/widget/genericchatroomwidget.h +++ b/widget/genericchatroomwidget.h @@ -17,7 +17,7 @@ #ifndef GENERICCHATROOMWIDGET_H #define GENERICCHATROOMWIDGET_H -#include +#include #include #include #include @@ -29,7 +29,7 @@ namespace Ui { class MainWindow; } -class GenericChatroomWidget : public QWidget +class GenericChatroomWidget : public QFrame { Q_OBJECT public: From 626cc248940cb295dff41d3b6adfa6656ccb911b Mon Sep 17 00:00:00 2001 From: dubslow Date: Wed, 1 Oct 2014 16:53:38 -0500 Subject: [PATCH 157/205] reduce dependency versions to debian stable versions --- debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/control b/debian/control index af90ab856..bb17b1441 100644 --- a/debian/control +++ b/debian/control @@ -7,7 +7,7 @@ Build-Depends: debhelper (>= 9), cdbs, qt5-qmake, libopenal-dev (>= 1:1.15.1), l Package: qtox Architecture: any -Depends: libc6 (>= 2.17), libgcc1 (>= 1:4.1.1), libgl1-mesa-glx | libgl1, libopenal1 (>= 1.14), libopencv-core2.4, libopencv-highgui2.4, libopus0 (>= 1.0), libqt5core5a (>= 5.2), libqt5gui5 (>= 5.2), libqt5network5 (>= 5.0), libqt5widgets5 (>= 5.2), libqt5xml5 (>= 5.0), libstdc++6 (>= 4.9), libvpx1 (>= 1.0.0) +Depends: libc6 (>= 2.13-38+deb7u4), libgcc1 (>= 1:4.1.1), libgl1-mesa-glx | libgl1, libopenal1 (>= 1.14), libopencv-core2.3, libopencv-highgui2.3, libopus0 (>= 0.9.14+20120615-1+nmu1), libqt5core5a (>= 5.2), libqt5gui5 (>= 5.2), libqt5network5 (>= 5.0), libqt5widgets5 (>= 5.2), libqt5xml5 (>= 5.0), libstdc++6 (>= 4.7.2-5), libvpx1 (>= 1.0.0) Description: Tox client qTox is a powerful Tox client that follows the Tox design guidelines. Tox is a decentralized and encrypted replacement for Skype, supporting From 30f386677261398bdb9145b38cca44b78f4331d0 Mon Sep 17 00:00:00 2001 From: dubslow Date: Wed, 1 Oct 2014 23:21:43 -0500 Subject: [PATCH 158/205] restore bold names in chat --- ui/chatArea/innerStyle.css | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ui/chatArea/innerStyle.css b/ui/chatArea/innerStyle.css index fd0ca03ee..771068a1d 100644 --- a/ui/chatArea/innerStyle.css +++ b/ui/chatArea/innerStyle.css @@ -1,6 +1,7 @@ div.name { color: @black; - font: @big; + font: @bigBold; + font-weight: bold; /* @bigBold doesn't actually work */ } div.message { @@ -19,12 +20,12 @@ div.name_me { } div.message_me { - color: @mediumGrey; + color: @black; font: @big; } div.date_me { - color: @mediumGrey; + color: @black; font: @big; } From 5f106ab6183b202e35f3e712a779249c91d7ea68 Mon Sep 17 00:00:00 2001 From: dubslow Date: Thu, 2 Oct 2014 01:01:23 -0500 Subject: [PATCH 159/205] add receive actions (no one to test with currently) --- core.cpp | 4 +- core.h | 4 +- qtox.pro | 2 + ui/chatArea/innerStyle.css | 5 ++ widget/form/genericchatform.cpp | 9 ++-- widget/form/genericchatform.h | 2 +- widget/tool/chatactions/actionaction.cpp | 68 ++++++++++++++++++++++++ widget/tool/chatactions/actionaction.h | 35 ++++++++++++ widget/widget.cpp | 4 +- widget/widget.h | 2 +- 10 files changed, 123 insertions(+), 12 deletions(-) create mode 100644 widget/tool/chatactions/actionaction.cpp create mode 100644 widget/tool/chatactions/actionaction.h diff --git a/core.cpp b/core.cpp index 53214dd3d..f6b7a2a5c 100644 --- a/core.cpp +++ b/core.cpp @@ -313,7 +313,7 @@ void Core::onFriendRequest(Tox*/* tox*/, const uint8_t* cUserId, const uint8_t* void Core::onFriendMessage(Tox*/* tox*/, int friendId, const uint8_t* cMessage, uint16_t cMessageSize, void* core) { - emit static_cast(core)->friendMessageReceived(friendId, CString::toString(cMessage, cMessageSize)); + emit static_cast(core)->friendMessageReceived(friendId, CString::toString(cMessage, cMessageSize), false); } void Core::onFriendNameChange(Tox*/* tox*/, int friendId, const uint8_t* cName, uint16_t cNameSize, void* core) @@ -393,7 +393,7 @@ void Core::onConnectionStatusChanged(Tox*/* tox*/, int friendId, uint8_t status, void Core::onAction(Tox*/* tox*/, int friendId, const uint8_t *cMessage, uint16_t cMessageSize, void *core) { - emit static_cast(core)->actionReceived(friendId, CString::toString(cMessage, cMessageSize)); + emit static_cast(core)->friendMessageReceived(friendId, CString::toString(cMessage, cMessageSize), true); } void Core::onGroupInvite(Tox*, int friendnumber, const uint8_t *group_public_key, uint16_t length,void *core) diff --git a/core.h b/core.h index 71692c3b2..b1b8c3f43 100644 --- a/core.h +++ b/core.h @@ -99,7 +99,7 @@ signals: void disconnected(); void friendRequestReceived(const QString& userId, const QString& message); - void friendMessageReceived(int friendId, const QString& message); + void friendMessageReceived(int friendId, const QString& message, bool isAction); void friendAdded(int friendId, const QString& userId); @@ -137,8 +137,6 @@ signals: void failedToSetStatus(Status status); void failedToSetTyping(bool typing); - void actionReceived(int friendId, const QString& acionMessage); - void failedToStart(); void fileSendStarted(ToxFile file); diff --git a/qtox.pro b/qtox.pro index 4c4db4492..e08e1f24e 100644 --- a/qtox.pro +++ b/qtox.pro @@ -119,6 +119,7 @@ HEADERS += widget/form/addfriendform.h \ widget/tool/chatactions/messageaction.h \ widget/tool/chatactions/filetransferaction.h \ widget/tool/chatactions/systemmessageaction.h \ + widget/tool/chatactions/actionaction.h \ widget/maskablepixmapwidget.h SOURCES += \ @@ -160,4 +161,5 @@ SOURCES += \ widget/tool/chatactions/messageaction.cpp \ widget/tool/chatactions/filetransferaction.cpp \ widget/tool/chatactions/systemmessageaction.cpp \ + widget/tool/chatactions/actionaction.cpp \ widget/maskablepixmapwidget.cpp diff --git a/ui/chatArea/innerStyle.css b/ui/chatArea/innerStyle.css index 771068a1d..5775f41f3 100644 --- a/ui/chatArea/innerStyle.css +++ b/ui/chatArea/innerStyle.css @@ -9,6 +9,11 @@ div.message { font: @big; } +div.action { + color: @blue; + font: @big; +} + div.date { color: @black; font: @big; diff --git a/widget/form/genericchatform.cpp b/widget/form/genericchatform.cpp index a7bcb5e2b..923089728 100644 --- a/widget/form/genericchatform.cpp +++ b/widget/form/genericchatform.cpp @@ -24,6 +24,7 @@ #include "misc/settings.h" #include "widget/tool/chatactions/messageaction.h" #include "widget/tool/chatactions/systemmessageaction.h" +#include "widget/tool/chatactions/actionaction.h" #include "widget/chatareawidget.h" #include "widget/tool/chattextedit.h" #include "widget/maskablepixmapwidget.h" @@ -166,15 +167,17 @@ void GenericChatForm::onSaveLogClicked() file.close(); } -void GenericChatForm::addMessage(QString author, QString message, QDateTime datetime) +void GenericChatForm::addMessage(QString author, QString message, bool isAction, QDateTime datetime) { QString date = datetime.toString(Settings::getInstance().getTimestampFormat()); bool isMe = (author == Widget::getInstance()->getUsername()); - if (previousName == author) + if (isAction) + chatWidget->insertMessage(new ActionAction (getElidedName(author), message, date, isMe)); + else if (previousName == author) chatWidget->insertMessage(new MessageAction("", message, date, isMe)); else - chatWidget->insertMessage(new MessageAction(getElidedName(author) , message, date, isMe)); + chatWidget->insertMessage(new MessageAction(getElidedName(author), message, date, isMe)); previousName = author; } diff --git a/widget/form/genericchatform.h b/widget/form/genericchatform.h index 2111bcdf9..863c90a0d 100644 --- a/widget/form/genericchatform.h +++ b/widget/form/genericchatform.h @@ -44,7 +44,7 @@ public: virtual void setName(const QString &newName); virtual void show(Ui::MainWindow &ui); - void addMessage(QString author, QString message, QDateTime datetime=QDateTime::currentDateTime()); + void addMessage(QString author, QString message, bool isAction = false, QDateTime datetime=QDateTime::currentDateTime()); void addSystemInfoMessage(const QString &message, const QString &type, const QDateTime &datetime=QDateTime::currentDateTime()); signals: diff --git a/widget/tool/chatactions/actionaction.cpp b/widget/tool/chatactions/actionaction.cpp new file mode 100644 index 000000000..754966107 --- /dev/null +++ b/widget/tool/chatactions/actionaction.cpp @@ -0,0 +1,68 @@ +/* + Copyright (C) 2014 by Project Tox + + This file is part of qTox, a Qt-based graphical interface for Tox. + + This program 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. + 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 COPYING file for more details. +*/ + +#include "actionaction.h" +#include "misc/smileypack.h" + +ActionAction::ActionAction(const QString &author, const QString &message, const QString &date, const bool& me) : + ChatAction(me, author, date), + message(message) +{ +} + +void ActionAction::setup(QTextCursor cursor, QTextEdit *) +{ + // When this function is called, we're supposed to only update ourselve when needed + // Nobody should ask us to do anything with our content, we're on our own + // Except we never udpate on our own, so we can safely free our resources + + (void) cursor; + message.clear(); + message.squeeze(); + name.clear(); + name.squeeze(); + date.clear(); + date.squeeze(); +} + +QString ActionAction::getName() +{ + return QString("
-*-
"); +} + +QString ActionAction::getMessage() +{ + QString message_ = SmileyPack::getInstance().smileyfied(toHtmlChars(message)); + + // detect urls + QRegExp exp("(www\\.|http[s]?:\\/\\/|ftp:\\/\\/)\\S+"); + int offset = 0; + while ((offset = exp.indexIn(message_, offset)) != -1) + { + QString url = exp.cap(); + + // add scheme if not specified + if (exp.cap(1) == "www.") + url.prepend("http://"); + + QString htmledUrl = QString("%1").arg(url); + message_.replace(offset, exp.cap().length(), htmledUrl); + + offset += htmledUrl.length(); + } + + return QString("
%1 %2
").arg(name).arg(message_); +} diff --git a/widget/tool/chatactions/actionaction.h b/widget/tool/chatactions/actionaction.h new file mode 100644 index 000000000..ec4e5f4a8 --- /dev/null +++ b/widget/tool/chatactions/actionaction.h @@ -0,0 +1,35 @@ +/* + Copyright (C) 2014 by Project Tox + + This file is part of qTox, a Qt-based graphical interface for Tox. + + This program 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. + 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 COPYING file for more details. +*/ + +#ifndef ACTIONACTION_H +#define ACTIONACTION_H + +#include "widget/tool/chatactions/chataction.h" + +class ActionAction : public ChatAction +{ +public: + ActionAction(const QString &author, const QString &message, const QString& date, const bool&); + virtual ~ActionAction(){;} + virtual QString getMessage(); + virtual QString getName(); + virtual void setup(QTextCursor cursor, QTextEdit*) override; + +private: + QString message; +}; + +#endif // MESSAGEACTION_H diff --git a/widget/widget.cpp b/widget/widget.cpp index e2c4770e9..e16a33c88 100644 --- a/widget/widget.cpp +++ b/widget/widget.cpp @@ -545,13 +545,13 @@ void Widget::onChatroomWidgetClicked(GenericChatroomWidget *widget) widget->updateStatusLight(); } -void Widget::onFriendMessageReceived(int friendId, const QString& message) +void Widget::onFriendMessageReceived(int friendId, const QString& message, bool isAction) { Friend* f = FriendList::findFriend(friendId); if (!f) return; - f->chatForm->addMessage(f->getName(), message); + f->chatForm->addMessage(f->getName(), message, isAction); if (activeChatroomWidget != nullptr) { diff --git a/widget/widget.h b/widget/widget.h index 5141e49f0..41289c9cd 100644 --- a/widget/widget.h +++ b/widget/widget.h @@ -93,7 +93,7 @@ private slots: void onFriendStatusMessageChanged(int friendId, const QString& message); void onFriendUsernameChanged(int friendId, const QString& username); void onChatroomWidgetClicked(GenericChatroomWidget *); - void onFriendMessageReceived(int friendId, const QString& message); + void onFriendMessageReceived(int friendId, const QString& message, bool isAction); void onFriendRequestReceived(const QString& userId, const QString& message); void onEmptyGroupCreated(int groupId); void onGroupInviteReceived(int32_t friendId, const uint8_t *publicKey,uint16_t length); From cfa39460bfeded9410c5f2cc719b63aa456dfb43 Mon Sep 17 00:00:00 2001 From: dubslow Date: Thu, 2 Oct 2014 02:00:06 -0500 Subject: [PATCH 160/205] added sending actions, and tested both ways --- ui/chatArea/innerStyle.css | 2 +- widget/form/chatform.cpp | 13 +++++++++++-- widget/form/genericchatform.cpp | 4 ++++ widget/form/genericchatform.h | 1 + widget/widget.cpp | 1 + 5 files changed, 18 insertions(+), 3 deletions(-) diff --git a/ui/chatArea/innerStyle.css b/ui/chatArea/innerStyle.css index 5775f41f3..9c8ae6753 100644 --- a/ui/chatArea/innerStyle.css +++ b/ui/chatArea/innerStyle.css @@ -10,7 +10,7 @@ div.message { } div.action { - color: @blue; + color: #1818FF; font: @big; } diff --git a/widget/form/chatform.cpp b/widget/form/chatform.cpp index f2f2c32d6..f309ce94a 100644 --- a/widget/form/chatform.cpp +++ b/widget/form/chatform.cpp @@ -86,9 +86,18 @@ void ChatForm::onSendTriggered() if (msg.isEmpty()) return; QString name = Widget::getInstance()->getUsername(); + if (msg.startsWith("/me ")) + { + msg = msg.right(msg.length() - 4); + addMessage(name, msg, true); + emit sendAction(f->friendId, msg); + } + else + { + addMessage(name, msg, false); + emit sendMessage(f->friendId, msg); + } msgEdit->clear(); - addMessage(name, msg); - emit sendMessage(f->friendId, msg); } void ChatForm::onAttachClicked() diff --git a/widget/form/genericchatform.cpp b/widget/form/genericchatform.cpp index 923089728..8c3753b0b 100644 --- a/widget/form/genericchatform.cpp +++ b/widget/form/genericchatform.cpp @@ -173,7 +173,11 @@ void GenericChatForm::addMessage(QString author, QString message, bool isAction, bool isMe = (author == Widget::getInstance()->getUsername()); if (isAction) + { chatWidget->insertMessage(new ActionAction (getElidedName(author), message, date, isMe)); + previousName = ""; // next msg has a name regardless + return; + } else if (previousName == author) chatWidget->insertMessage(new MessageAction("", message, date, isMe)); else diff --git a/widget/form/genericchatform.h b/widget/form/genericchatform.h index 863c90a0d..b8c373d23 100644 --- a/widget/form/genericchatform.h +++ b/widget/form/genericchatform.h @@ -49,6 +49,7 @@ public: signals: void sendMessage(int, QString); + void sendAction(int, QString); public slots: void focusInput(); diff --git a/widget/widget.cpp b/widget/widget.cpp index e16a33c88..606036b15 100644 --- a/widget/widget.cpp +++ b/widget/widget.cpp @@ -455,6 +455,7 @@ void Widget::addFriend(int friendId, const QString &userId) connect(newfriend->widget, SIGNAL(copyFriendIdToClipboard(int)), this, SLOT(copyFriendIdToClipboard(int))); connect(newfriend->widget, SIGNAL(chatroomWidgetClicked(GenericChatroomWidget*)), newfriend->chatForm, SLOT(focusInput())); connect(newfriend->chatForm, SIGNAL(sendMessage(int,QString)), core, SLOT(sendMessage(int,QString))); + connect(newfriend->chatForm, &GenericChatForm::sendAction, core, &Core::sendAction); connect(newfriend->chatForm, SIGNAL(sendFile(int32_t, QString, QString, long long)), core, SLOT(sendFile(int32_t, QString, QString, long long))); connect(newfriend->chatForm, SIGNAL(answerCall(int)), core, SLOT(answerCall(int))); connect(newfriend->chatForm, SIGNAL(hangupCall(int)), core, SLOT(hangupCall(int))); From daf5be96b51133f00c0c95beafceb65cdb9e6a85 Mon Sep 17 00:00:00 2001 From: krepa098 Date: Thu, 2 Oct 2014 09:37:18 +0200 Subject: [PATCH 161/205] Style: font size doesn't take px suffix, fixes fonts not applying properly --- misc/style.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/style.cpp b/misc/style.cpp index b4d1cc209..af34f79d5 100644 --- a/misc/style.cpp +++ b/misc/style.cpp @@ -46,7 +46,7 @@ QString qssifyWeight(int weight) QString qssifyFont(QFont font) { - return QString("%1px %2 \"%3\"") + return QString("%1 %2 \"%3\"") .arg(font.pixelSize()) .arg(qssifyWeight(font.weight())) .arg(font.family()); From 3127e023d867e0650108ebf977a9252e81f5a46d Mon Sep 17 00:00:00 2001 From: dubslow Date: Thu, 2 Oct 2014 14:27:03 -0500 Subject: [PATCH 162/205] Revert "reduce dependency versions to debian stable versions" This reverts commit 626cc248940cb295dff41d3b6adfa6656ccb911b. --- debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/control b/debian/control index bb17b1441..af90ab856 100644 --- a/debian/control +++ b/debian/control @@ -7,7 +7,7 @@ Build-Depends: debhelper (>= 9), cdbs, qt5-qmake, libopenal-dev (>= 1:1.15.1), l Package: qtox Architecture: any -Depends: libc6 (>= 2.13-38+deb7u4), libgcc1 (>= 1:4.1.1), libgl1-mesa-glx | libgl1, libopenal1 (>= 1.14), libopencv-core2.3, libopencv-highgui2.3, libopus0 (>= 0.9.14+20120615-1+nmu1), libqt5core5a (>= 5.2), libqt5gui5 (>= 5.2), libqt5network5 (>= 5.0), libqt5widgets5 (>= 5.2), libqt5xml5 (>= 5.0), libstdc++6 (>= 4.7.2-5), libvpx1 (>= 1.0.0) +Depends: libc6 (>= 2.17), libgcc1 (>= 1:4.1.1), libgl1-mesa-glx | libgl1, libopenal1 (>= 1.14), libopencv-core2.4, libopencv-highgui2.4, libopus0 (>= 1.0), libqt5core5a (>= 5.2), libqt5gui5 (>= 5.2), libqt5network5 (>= 5.0), libqt5widgets5 (>= 5.2), libqt5xml5 (>= 5.0), libstdc++6 (>= 4.9), libvpx1 (>= 1.0.0) Description: Tox client qTox is a powerful Tox client that follows the Tox design guidelines. Tox is a decentralized and encrypted replacement for Skype, supporting From 8aba636c638732541af0cde7a4996b3172b777ce Mon Sep 17 00:00:00 2001 From: dubslow Date: Thu, 2 Oct 2014 18:53:44 -0500 Subject: [PATCH 163/205] fix groupchat issue --- widget/widget.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/widget/widget.cpp b/widget/widget.cpp index 606036b15..555042ef8 100644 --- a/widget/widget.cpp +++ b/widget/widget.cpp @@ -176,6 +176,7 @@ Widget::Widget(QWidget *parent) qRegisterMetaType("Status"); qRegisterMetaType("vpx_image"); qRegisterMetaType("uint8_t"); + qRegisterMetaType("uint16_t"); qRegisterMetaType("int32_t"); qRegisterMetaType("int64_t"); qRegisterMetaType("QPixmap"); From 2ebc583f291b4ab78eb05006e1238d5702ba9793 Mon Sep 17 00:00:00 2001 From: krepa098 Date: Fri, 3 Oct 2014 16:31:42 +0200 Subject: [PATCH 164/205] fixed #372 --- misc/style.cpp | 29 +++++++++++------------------ ui/chatArea/innerStyle.css | 1 - 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/misc/style.cpp b/misc/style.cpp index af34f79d5..b1c49bebc 100644 --- a/misc/style.cpp +++ b/misc/style.cpp @@ -33,22 +33,11 @@ QFont appFont(int pixelSize, int weight) return font; } -QString qssifyWeight(int weight) -{ - QString weightStr = "normal"; - if (weight == QFont::Bold) - weightStr = "bold"; - if (weight == QFont::Light) - weightStr = "light"; - - return QString("%1").arg(weightStr); -} - QString qssifyFont(QFont font) { - return QString("%1 %2 \"%3\"") + return QString("%1 %2px \"%3\"") + .arg(font.weight()*10) .arg(font.pixelSize()) - .arg(qssifyWeight(font.weight())) .arg(font.family()); } @@ -68,6 +57,8 @@ QString Style::getStylesheet(const QString &filename) QColor Style::getColor(Style::ColorPalette entry) { + // colors as defined in + // https://github.com/ItsDuke/Tox-UI/blob/master/UI%20GUIDELINES.md static QColor palette[] = { QColor("#6bc260"), QColor("#cebf44"), @@ -85,14 +76,16 @@ QColor Style::getColor(Style::ColorPalette entry) QFont Style::getFont(Style::Font font) { + // fonts as defined in + // https://github.com/ItsDuke/Tox-UI/blob/master/UI%20GUIDELINES.md static QFont fonts[] = { + appFont(15, QFont::Bold), + appFont(14, QFont::Normal), appFont(14, QFont::Bold), + appFont(13, QFont::Normal), + appFont(13, QFont::Bold), appFont(12, QFont::Normal), - appFont(12, QFont::Bold), - appFont(11, QFont::Normal), - appFont(11, QFont::Bold), - appFont(10, QFont::Normal), - appFont(10, QFont::Light), + appFont(12, QFont::Light), }; return fonts[font]; diff --git a/ui/chatArea/innerStyle.css b/ui/chatArea/innerStyle.css index 9c8ae6753..03db4367b 100644 --- a/ui/chatArea/innerStyle.css +++ b/ui/chatArea/innerStyle.css @@ -1,7 +1,6 @@ div.name { color: @black; font: @bigBold; - font-weight: bold; /* @bigBold doesn't actually work */ } div.message { From 300d045dd97b27cb17e4872331b09590973825c0 Mon Sep 17 00:00:00 2001 From: krepa098 Date: Fri, 3 Oct 2014 21:04:01 +0200 Subject: [PATCH 165/205] FileTransferInstance: return of the edges --- filetransferinstance.cpp | 27 +++++++++++++++++++++-- res.qrc | 1 + ui/fileTransferInstance/sliverRTEdge.png | Bin 0 -> 225 bytes 3 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 ui/fileTransferInstance/sliverRTEdge.png diff --git a/filetransferinstance.cpp b/filetransferinstance.cpp index 9ab0c75d3..22570aa53 100644 --- a/filetransferinstance.cpp +++ b/filetransferinstance.cpp @@ -391,10 +391,33 @@ QString FileTransferInstance::draw2ButtonsForm(const QString &type, const QImage QString FileTransferInstance::wrapIntoForm(const QString& content, const QString &type, const QString &imgAstr, const QString &imgBstr) { - QString res; + QString w = QString::number(QImage(":/ui/fileTransferInstance/emptyLRedFileButton.png").size().width()); + QString imgLeftA, imgLeftB; + if (type == "green") + { + imgLeftA = ""; + imgLeftB = ""; + } + + if (type == "silver") + { + imgLeftA = ""; + imgLeftB = ""; + } + + if (type == "red") + { + imgLeftA = ""; + imgLeftB = ""; + } + + QString res; res = "\n"; res += "\n"; + res += "\n"; res += insertMiniature(type); res += "\n"; res += "\n"; res += "\n"; res += "
\n"; + res += "
" + imgLeftA + "
" + imgLeftB + "
\n"; + res += "
\n"; res += "
"; @@ -402,7 +425,7 @@ QString FileTransferInstance::wrapIntoForm(const QString& content, const QString res += "
\n"; res += "
\n"; - res += "
" + imgAstr + "
" + imgBstr+ "
\n"; + res += "
" + imgAstr + "
" + imgBstr + "
\n"; res += "
\n"; diff --git a/res.qrc b/res.qrc index 5b4910039..17c26eb2c 100644 --- a/res.qrc +++ b/res.qrc @@ -146,5 +146,6 @@ img/avatar_mask.png img/group_2x.png ui/chatroomWidgets/genericChatroomWidget.css + ui/fileTransferInstance/sliverRTEdge.png diff --git a/ui/fileTransferInstance/sliverRTEdge.png b/ui/fileTransferInstance/sliverRTEdge.png new file mode 100644 index 0000000000000000000000000000000000000000..dd363d10799f5c83d81844040df4367462483a93 GIT binary patch literal 225 zcmeAS@N?(olHy`uVBq!ia0vp^l0YoO!3HF!sEAwuQfx`y?k)`fL2$v|<&%LToCO|{ z#S9F5M?jcysy3fAP>{XE)7O>#9v8Eaf!XHWTYz#5d7dtgAs)xyURWr2$U(&Q;^Y-e z1SaIjera?K=9uIZbbPzZa<+m6M$HcI*8RF}SD1EBKv2H4>TxIQ_n=eT_!n3CT0Cqs zRnpU)a6iqaEMrB*_5E=cJ-5sr-;!!9=6`a7d1jS@kf+K-7ZCC8gt!5(XwS7B3=e=d OGkCiCxvX Date: Sat, 4 Oct 2014 10:24:20 +0200 Subject: [PATCH 166/205] statusPanel: css, cleanup --- mainwindow.ui | 1293 +------------------------------------ misc/style.cpp | 2 +- res.qrc | 1 + ui/window/statusPanel.css | 70 ++ widget/widget.cpp | 58 +- 5 files changed, 96 insertions(+), 1328 deletions(-) create mode 100644 ui/window/statusPanel.css diff --git a/mainwindow.ui b/mainwindow.ui index 300cc60c3..f8f1f72f6 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -6,8 +6,8 @@ 0 0 - 712 - 539 + 710 + 537 @@ -548,458 +548,13 @@ QSplitter:handle{ false - + 0 0 - - - - - - - 255 - 255 - 255 - - - - - - - 28 - 28 - 28 - - - - - - - 42 - 42 - 42 - - - - - - - 35 - 35 - 35 - - - - - - - 14 - 14 - 14 - - - - - - - 18 - 18 - 18 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 0 - - - - - - - 28 - 28 - 28 - - - - - - - 0 - 0 - 0 - - - - - - - 14 - 14 - 14 - - - - - - - 28 - 28 - 28 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - - - 255 - 255 - 255 - - - - - - - 28 - 28 - 28 - - - - - - - 42 - 42 - 42 - - - - - - - 35 - 35 - 35 - - - - - - - 14 - 14 - 14 - - - - - - - 18 - 18 - 18 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 0 - - - - - - - 28 - 28 - 28 - - - - - - - 0 - 0 - 0 - - - - - - - 14 - 14 - 14 - - - - - - - 28 - 28 - 28 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - - - 14 - 14 - 14 - - - - - - - 28 - 28 - 28 - - - - - - - 42 - 42 - 42 - - - - - - - 35 - 35 - 35 - - - - - - - 14 - 14 - 14 - - - - - - - 18 - 18 - 18 - - - - - - - 14 - 14 - 14 - - - - - - - 255 - 255 - 255 - - - - - - - 14 - 14 - 14 - - - - - - - 28 - 28 - 28 - - - - - - - 28 - 28 - 28 - - - - - - - 0 - 0 - 0 - - - - - - - 28 - 28 - 28 - - - - - - - 28 - 28 - 28 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - - true - 0 @@ -1027,424 +582,6 @@ QSplitter:handle{ 0 - - - - - - - 255 - 255 - 255 - - - - - - - 28 - 28 - 28 - - - - - - - 42 - 42 - 42 - - - - - - - 35 - 35 - 35 - - - - - - - 14 - 14 - 14 - - - - - - - 18 - 18 - 18 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 0 - - - - - - - 28 - 28 - 28 - - - - - - - 0 - 0 - 0 - - - - - - - 14 - 14 - 14 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - - - 255 - 255 - 255 - - - - - - - 28 - 28 - 28 - - - - - - - 42 - 42 - 42 - - - - - - - 35 - 35 - 35 - - - - - - - 14 - 14 - 14 - - - - - - - 18 - 18 - 18 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 0 - - - - - - - 28 - 28 - 28 - - - - - - - 0 - 0 - 0 - - - - - - - 14 - 14 - 14 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - - - 14 - 14 - 14 - - - - - - - 28 - 28 - 28 - - - - - - - 42 - 42 - 42 - - - - - - - 35 - 35 - 35 - - - - - - - 14 - 14 - 14 - - - - - - - 18 - 18 - 18 - - - - - - - 14 - 14 - 14 - - - - - - - 255 - 255 - 255 - - - - - - - 14 - 14 - 14 - - - - - - - 28 - 28 - 28 - - - - - - - 28 - 28 - 28 - - - - - - - 0 - 0 - 0 - - - - - - - 28 - 28 - 28 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - - true - @@ -2083,8 +1220,8 @@ QSplitter:handle{ 0 0 - 261 - 373 + 288 + 371 @@ -2102,424 +1239,6 @@ QSplitter:handle{ 0 - - - - - - - 255 - 255 - 255 - - - - - - - 28 - 28 - 28 - - - - - - - 42 - 42 - 42 - - - - - - - 35 - 35 - 35 - - - - - - - 14 - 14 - 14 - - - - - - - 18 - 18 - 18 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 0 - - - - - - - 28 - 28 - 28 - - - - - - - 0 - 0 - 0 - - - - - - - 14 - 14 - 14 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - - - 255 - 255 - 255 - - - - - - - 28 - 28 - 28 - - - - - - - 42 - 42 - 42 - - - - - - - 35 - 35 - 35 - - - - - - - 14 - 14 - 14 - - - - - - - 18 - 18 - 18 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 0 - - - - - - - 28 - 28 - 28 - - - - - - - 0 - 0 - 0 - - - - - - - 14 - 14 - 14 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - - - 14 - 14 - 14 - - - - - - - 28 - 28 - 28 - - - - - - - 42 - 42 - 42 - - - - - - - 35 - 35 - 35 - - - - - - - 14 - 14 - 14 - - - - - - - 18 - 18 - 18 - - - - - - - 14 - 14 - 14 - - - - - - - 255 - 255 - 255 - - - - - - - 14 - 14 - 14 - - - - - - - 28 - 28 - 28 - - - - - - - 28 - 28 - 28 - - - - - - - 0 - 0 - 0 - - - - - - - 28 - 28 - 28 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - - true - 0 @@ -3218,7 +1937,7 @@ QSplitter:handle{ 0 0 - 712 + 710 25 diff --git a/misc/style.cpp b/misc/style.cpp index b1c49bebc..120991f65 100644 --- a/misc/style.cpp +++ b/misc/style.cpp @@ -79,7 +79,7 @@ QFont Style::getFont(Style::Font font) // fonts as defined in // https://github.com/ItsDuke/Tox-UI/blob/master/UI%20GUIDELINES.md static QFont fonts[] = { - appFont(15, QFont::Bold), + appFont(16, QFont::Bold), appFont(14, QFont::Normal), appFont(14, QFont::Bold), appFont(13, QFont::Normal), diff --git a/res.qrc b/res.qrc index 17c26eb2c..312ec457a 100644 --- a/res.qrc +++ b/res.qrc @@ -147,5 +147,6 @@ img/group_2x.png ui/chatroomWidgets/genericChatroomWidget.css ui/fileTransferInstance/sliverRTEdge.png + ui/window/statusPanel.css diff --git a/ui/window/statusPanel.css b/ui/window/statusPanel.css new file mode 100644 index 000000000..3a0fc36da --- /dev/null +++ b/ui/window/statusPanel.css @@ -0,0 +1,70 @@ +#statusPanel +{ + background-color: @darkGrey; +} + +#statusPanel > #statusHead > #nameLabel { + font: @extraBig; + color: @white; +} + +#statusPanel > #statusHead > #statusLabel { + font: @smallLight; + color: @lightGrey; +} + +#statusPanel > #statusHead > #statusButton +{ + background: none; + background-color: @mediumGrey; + border: none; + border-radius: 6px; + width: 20px; + height: 40px; +} + +#statusPanel > #statusHead > #statusButton[status="online"] +{ + image: url(":ui/statusButton/dot_online.png") center center; +} + +#statusPanel > #statusHead > #statusButton[status="away"] +{ + image: url(":ui/statusButton/dot_idle.png") center center; +} + +#statusPanel > #statusHead > #statusButton[status="busy"] +{ + image: url(":ui/statusButton/dot_busy.png") center center; +} + +#statusPanel > #statusHead > #statusButton[status="offline"] +{ + image: url(":ui/statusButton/dot_away.png") center center; +} + +/*Bugged in Qt, but it's probably better to leave enabled so that users can tell it's clickable*/ +#statusPanel > #statusHead > #statusButton:hover +{ + background-color: @mediumGreyLight; +} + +#statusPanel > #statusHead > #statusButton:pressed +{ + background-color: @mediumGrey; +} + +#statusPanel > #statusHead > #statusButton:focus { + outline: none; +} + +#statusPanel > #statusHead > #statusButton::menu-indicator {image: none;} + +#statusPanel > #statusHead > #statusButton::menu-indicator:pressed, #statusPanel > #statusHead > #statusButton::menu-indicator:open +{ + image: url(":ui/statusButton/menu_indicator.png"); + subcontrol-origin: padding; + subcontrol-position: bottom center; + position: relative; + bottom: 2px; +} diff --git a/widget/widget.cpp b/widget/widget.cpp index 555042ef8..92c1ed95b 100644 --- a/widget/widget.cpp +++ b/widget/widget.cpp @@ -130,16 +130,7 @@ Widget::Widget(QWidget *parent) ui->nameLabel->setEditable(true); ui->statusLabel->setEditable(true); - ui->statusLabel->setFont(Style::getFont(Style::Medium)); - ui->nameLabel->setFont(Style::getFont(Style::ExtraBig)); - - // delay setting username and message until Core inits - //ui->nameLabel->setText(core->getUsername()); - ui->nameLabel->setStyleSheet("QLabel { color : white; font-size: 11pt; font-weight:bold;}"); - //ui->statusLabel->setText(core->getStatusMessage()); - ui->statusLabel->setStyleSheet("QLabel { color : white; font-size: 8pt;}"); - - ui->statusButton->setStyleSheet(Style::getStylesheet(":/ui/statusButton/statusButton.css")); + ui->statusPanel->setStyleSheet(Style::getStylesheet(":/ui/window/statusPanel.css")); QMenu *statusButtonMenu = new QMenu(ui->statusButton); QAction* setStatusOnline = statusButtonMenu->addAction(Widget::tr("Online","Button to set your status to 'Online'")); @@ -150,22 +141,12 @@ Widget::Widget(QWidget *parent) setStatusBusy->setIcon(QIcon(":ui/statusButton/dot_busy.png")); ui->statusButton->setMenu(statusButtonMenu); - ui->titleBar->setMouseTracking(true); - ui->LTitle->setMouseTracking(true); - ui->tbMenu->setMouseTracking(true); - ui->pbMin->setMouseTracking(true); - ui->pbMax->setMouseTracking(true); - ui->pbClose->setMouseTracking(true); - ui->statusHead->setMouseTracking(true); - - //ui->friendList->viewport()->installEventFilter(this); - // disable proportional scaling ui->mainSplitter->setStretchFactor(0,0); ui->mainSplitter->setStretchFactor(1,1); - ui->statusButton->setObjectName("offline"); - ui->statusButton->style()->polish(ui->statusButton); + ui->statusButton->setProperty("status", "offline"); + Style::repolish(ui->statusButton); camera = new Camera; settingsDialog = new SettingsDialog(this); @@ -359,26 +340,23 @@ void Widget::onStatusSet(Status status) { //We have to use stylesheets here, there's no way to //prevent the button icon from moving when pressed otherwise - if (status == Status::Online) + switch (status) { - ui->statusButton->setObjectName("online"); - ui->statusButton->style()->polish(ui->statusButton); - } - else if (status == Status::Away) - { - ui->statusButton->setObjectName("away"); - ui->statusButton->style()->polish(ui->statusButton); - } - else if (status == Status::Busy) - { - ui->statusButton->setObjectName("busy"); - ui->statusButton->style()->polish(ui->statusButton); - } - else if (status == Status::Offline) - { - ui->statusButton->setObjectName("offline"); - ui->statusButton->style()->polish(ui->statusButton); + case Status::Online: + ui->statusButton->setProperty("status" ,"online"); + break; + case Status::Away: + ui->statusButton->setProperty("status" ,"away"); + break; + case Status::Busy: + ui->statusButton->setProperty("status" ,"busy"); + break; + case Status::Offline: + ui->statusButton->setProperty("status" ,"offline"); + break; } + + Style::repolish(ui->statusButton); } void Widget::onAddClicked() From 23a64ef45fa7600859e1bf6a679c2e835f60a4d4 Mon Sep 17 00:00:00 2001 From: krepa098 Date: Sat, 4 Oct 2014 10:54:50 +0200 Subject: [PATCH 167/205] removed broken custom window decoration --- mainwindow.ui | 189 +----------- misc/settings.cpp | 12 - misc/settings.h | 4 - res.qrc | 12 - ui/window/closeButton.png | Bin 385 -> 0 bytes ui/window/closeButtonHover.png | Bin 370 -> 0 bytes ui/window/closeButtonPressed.png | Bin 372 -> 0 bytes ui/window/maximizeButton.png | Bin 401 -> 0 bytes ui/window/maximizeButtonHover.png | Bin 401 -> 0 bytes ui/window/maximizeButtonPressed.png | Bin 402 -> 0 bytes ui/window/minimizeButton.png | Bin 371 -> 0 bytes ui/window/minimizeButtonHover.png | Bin 371 -> 0 bytes ui/window/minimizeButtonPressed.png | Bin 372 -> 0 bytes ui/window/restoreButton.png | Bin 401 -> 0 bytes ui/window/restoreButtonHover.png | Bin 401 -> 0 bytes ui/window/restoreButtonPressed.png | Bin 402 -> 0 bytes widget/form/chatform.cpp | 4 +- widget/groupwidget.cpp | 29 +- widget/widget.cpp | 430 +--------------------------- widget/widget.h | 25 +- 20 files changed, 21 insertions(+), 684 deletions(-) delete mode 100644 ui/window/closeButton.png delete mode 100644 ui/window/closeButtonHover.png delete mode 100644 ui/window/closeButtonPressed.png delete mode 100644 ui/window/maximizeButton.png delete mode 100644 ui/window/maximizeButtonHover.png delete mode 100644 ui/window/maximizeButtonPressed.png delete mode 100644 ui/window/minimizeButton.png delete mode 100644 ui/window/minimizeButtonHover.png delete mode 100644 ui/window/minimizeButtonPressed.png delete mode 100644 ui/window/restoreButton.png delete mode 100644 ui/window/restoreButtonHover.png delete mode 100644 ui/window/restoreButtonPressed.png diff --git a/mainwindow.ui b/mainwindow.ui index f8f1f72f6..78c16d345 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -37,193 +37,6 @@ 0 - - - - - 0 - 0 - - - - - 0 - 23 - - - - - 16777215 - 23 - - - - - 4 - - - 5 - - - 0 - - - 1 - - - 0 - - - - - - 16 - 16 - - - - - 16 - 16 - - - - - 16 - 16 - - - - QToolButton::InstantPopup - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 15 - 1 - - - - - - - - - 100 - 22 - - - - - 16777215 - 22 - - - - - - - - Qt::Horizontal - - - QSizePolicy::Minimum - - - - 134 - 20 - - - - - - - - - 22 - 22 - - - - - 22 - 22 - - - - - 22 - 22 - - - - true - - - - - - - - 22 - 22 - - - - - 22 - 22 - - - - - 22 - 22 - - - - true - - - - - - - - 22 - 22 - - - - - 22 - 22 - - - - - 22 - 22 - - - - true - - - - - - @@ -1221,7 +1034,7 @@ QSplitter:handle{ 0 0 288 - 371 + 400 diff --git a/misc/settings.cpp b/misc/settings.cpp index 31cbd158e..72a06e4ed 100644 --- a/misc/settings.cpp +++ b/misc/settings.cpp @@ -130,7 +130,6 @@ void Settings::load() timestampFormat = s.value("timestampFormat", "hh:mm").toString(); minimizeOnClose = s.value("minimizeOnClose", false).toBool(); useNativeStyle = s.value("nativeStyle", false).toBool(); - useNativeDecoration = s.value("nativeDecoration", true).toBool(); s.endGroup(); s.beginGroup("State"); @@ -230,7 +229,6 @@ void Settings::save(QString path) s.setValue("timestampFormat", timestampFormat); s.setValue("minimizeOnClose", minimizeOnClose); s.setValue("nativeStyle", useNativeStyle); - s.setValue("nativeDecoration", useNativeDecoration); s.endGroup(); s.beginGroup("State"); @@ -478,16 +476,6 @@ void Settings::setUseNativeStyle(bool value) useNativeStyle = value; } -bool Settings::getUseNativeDecoration() const -{ - return useNativeDecoration; -} - -void Settings::setUseNativeDecoration(bool value) -{ - useNativeDecoration = value; -} - QByteArray Settings::getWindowGeometry() const { return windowGeometry; diff --git a/misc/settings.h b/misc/settings.h index 9f379e886..f171c17af 100644 --- a/misc/settings.h +++ b/misc/settings.h @@ -121,9 +121,6 @@ public: bool getUseNativeStyle() const; void setUseNativeStyle(bool value); - bool getUseNativeDecoration() const; - void setUseNativeDecoration(bool value); - QByteArray getWindowGeometry() const; void setWindowGeometry(const QByteArray &value); @@ -170,7 +167,6 @@ private: int emojiFontPointSize; bool minimizeOnClose; bool useNativeStyle; - bool useNativeDecoration; QByteArray windowGeometry; QByteArray windowState; QByteArray splitterState; diff --git a/res.qrc b/res.qrc index 312ec457a..e8156ac58 100644 --- a/res.qrc +++ b/res.qrc @@ -84,18 +84,6 @@ ui/videoButton/videoButtonYellowPressed.png img/group_dark.png ui/window/applicationIcon.png - ui/window/closeButton.png - ui/window/closeButtonHover.png - ui/window/closeButtonPressed.png - ui/window/maximizeButton.png - ui/window/maximizeButtonHover.png - ui/window/maximizeButtonPressed.png - ui/window/minimizeButton.png - ui/window/minimizeButtonHover.png - ui/window/minimizeButtonPressed.png - ui/window/restoreButton.png - ui/window/restoreButtonHover.png - ui/window/restoreButtonPressed.png ui/friendList/friendList.css ui/window/window.css img/status/dot_busy.png diff --git a/ui/window/closeButton.png b/ui/window/closeButton.png deleted file mode 100644 index ce57b0e9e72cd37f84ef29e08d021ef035bbf152..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 385 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H1|*Mc$*~4fEa{HEjtmSN`?>!lvI6;>1s;*b z3=G^tAk28_ZrvZCAbW|YuPggqc1ccEv#WRImjZ<(OI#yLobz*YQ}ap~oQqNuOHxx5 z$}>wc6x=<11Hv2m#DR*$K#GF%(@M${i&7a15;OBk^zu?m6ioCCtY3W11gbdc>EamT z;l1_BM&3gXJggU{h)8xA=>~6Laou*xLQ``StH|;HLh48N^-mR8ULo}FhS(E}T|uWb zQ)W1}NrH&0uj^hXws20<-0CkJUboIYrLVIZ-vY7XNtu z!EOI>k(On9?ajZLZNDHQD)l`^pz`;u1&#J%Kd{#ozje$t?s$N0pD9hYhu`ep=m U>^0CV2YQOZ)78&qol`;+05=km-v9sr diff --git a/ui/window/closeButtonHover.png b/ui/window/closeButtonHover.png deleted file mode 100644 index 8b756f08b9e4bdf1418c9083ccfac03062e30a1a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 370 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H1|*Mc$*~4fEa{HEjtmSN`?>!lvI6;>1s;*b z3=G^tAk28_ZrvZCAbW|YuPggqc1ccEv#WRImjZ<(OI#yLobz*YQ}ap~oQqNuOHxx5 z$}>wc6x=<11Hv2m#DR*$K#GF%(@M${i&7a15;OBk^zu?m6ioCCtY3W11ghBO>EamT z;l1_BM&4!z9@clu$R**{ zkjMfeww_UrzIp6hvy8Xdp?SbtDnm{r-UW| D8Xtz3 diff --git a/ui/window/closeButtonPressed.png b/ui/window/closeButtonPressed.png deleted file mode 100644 index caa1e40744554c16099e678e8898026cb8ea62bf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 372 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H1|*Mc$*~4fEa{HEjtmSN`?>!lvI6;>1s;*b z3=G^tAk28_ZrvZCAbW|YuPggqc1ccEv#WRImjZ<(OI#yLobz*YQ}ap~oQqNuOHxx5 z$}>wc6x=<11Hv2m#DR*$K#GF%(@M${i&7a15;OBk^zu?m6ioCCtY3W11ghBM>EamT z;l1^WAz!lr4{N|NKA9ED(M4p08T9__#p>!r!U zV|(BNGmzLYzl4Ad)cHjQT9foR7o~4ZZo9&)-riC!Zp6I{7 zD>z$~-`ZVNX}`V6f~Tp^S2#U6>UdVSd+uVciQ#gl+jGkLv|JuM*brWr`Y{ct?$Mv; z$F7I%4iG)Mlb5MHUQ|Re`j@~b;a!|!lvI6;>1s;*b z3=G^tAk28_ZrvZCAbW|YuPggqc1ccFxzab2{{n?1OI#yLobz*YQ}ap~oQqNuOHxx5 z$}>wc6x=<11Hv2m#DR*$K#GF%(@M${i&7a15;OBk^zu?m6ioCCtY3W11gf~{>EamT z;l1_BLSCjo0hSBG94t&iT#iB_tO0D3m_B%PIRr4MDqLV`bWjoyX>h4Y6RJC;=lpK+ zZDIXHb!%1 z1#RxLzdCcJcRfS5tVONJ>kps5{FOBpnD$J5X^?jPah{f?z1mZ6{I*V0(3u;%^2p)) zhRlg8w;qlT*DCx_e#RjpYDZA#*8RzBhlJv9+s}W@=M2;%DfU?2qs{5h j+5}T19NW$=eZ^X__v`$H9AEi>o@DTJ^>bP0l+XkK9TJb^ diff --git a/ui/window/maximizeButtonHover.png b/ui/window/maximizeButtonHover.png deleted file mode 100644 index dae87a3b54d0aed6bf82c99d9dffc0f48ae977c8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 401 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H1|*Mc$*~4fEa{HEjtmSN`?>!lvI6;>1s;*b z3=G^tAk28_ZrvZCAbW|YuPggqc1ccFxzab2{{n?1OI#yLobz*YQ}ap~oQqNuOHxx5 z$}>wc6x=<11Hv2m#DR*$K#GF%(@M${i&7a15;OBk^zu?m6ioCCtY3W11gf~{>EamT z;l1_BLSCjo0hRz3rbdSc8BCon3YyHGj1?-b3K|VU0wN6#b6gZO7&?EPQTaakb}GmG zJM$_yt#3vao?JdX=v51k@(F_`5HUNXn=$7B$9JiEW9e0XYR*oDY@$o_^9;gcCn<6T zS6pSUi(Dlw&nWi0AXB9N;d9BK)@celYo(S3Mb{taX<52gd#VLkC^mNGk<0fDnG;uT zKFl7jRrsy^j6+1!?x4=O`;*xY3B}*GpZ}OK8K_56?6JH@o711k=K^~E3uk$^38qLm ew!K|?PkN3I=e3&*mg|9@WbkzLb6Mw<&;$UDIf%^w diff --git a/ui/window/maximizeButtonPressed.png b/ui/window/maximizeButtonPressed.png deleted file mode 100644 index 719b3f8bc8cf2195d484e1ac0df1c1d64cb03a92..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 402 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H1|*Mc$*~4fEa{HEjtmSN`?>!lvI6;>1s;*b z3=G^tAk28_ZrvZCAbW|YuPggqc1ccFxzab2{{n?1OI#yLobz*YQ}ap~oQqNuOHxx5 z$}>wc6x=<11Hv2m#DR*$K#GF%(@M${i&7a15;OBk^zu?m6ioCCtY3W11gf~@>EamT z;l1_BLf%6O0;~_XgakNPnnRQ%8w@A#G`JhFG%-prUSt&DP+>aA@Fbk$m)=X&y^kmU zTN3_J_0H+N!oGD~Q!XiFNHn$yf{3h`slqo7amw-j)V(>SRD_qci+jhx=k3-yk>M8v zT7~YNZPe2)d#run5r^K|B=Mg%#`VW}n7m(yX~_>rGrz8=KPg4=Fo|a)jWP0 zER@jRzi!InPvvJ6Hf$+eDpL*C@#)sTpECY4ep{ynMD)}vaJBwWUmMW#U-(rw#2tT^ aE@I1I+Vea~Vu=UPmkge+elF{r5}E+mN|D?E diff --git a/ui/window/minimizeButton.png b/ui/window/minimizeButton.png deleted file mode 100644 index 8773e5359ad2a88b312dd13d86d86e15eab892c0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 371 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H1|*Mc$*~4fEa{HEjtmSN`?>!lvI6;>1s;*b z3=G^tAk28_ZrvZCAbW|YuPggqc1ccFxzab2{{n?1OI#yLobz*YQ}ap~oQqNuOHxx5 z$}>wc6x=<11Hv2m#DR*$K#GF%(@M${i&7a15;OBk^zu?m6ioCCtY3W11ghBW>EamT z;l1^WAz!lr59@^JRz1H3$d^wl*we zm#6{}Vct?Vj-+kdc)oDXX2x$a2^!N(Hch?A|MLz`m|gkYp>kdeA9B3Kx6aaxTE&n<{+V{a=Id^dFz-L%wS(SG6Vgcpo$atRgkOJ)C^$&!hUW^M<1gTd3)&t;ucLK6Tz Cb%clj diff --git a/ui/window/minimizeButtonHover.png b/ui/window/minimizeButtonHover.png deleted file mode 100644 index 982c032b04daf140c24cd3e933ed9b05c3386df6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 371 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H1|*Mc$*~4fEa{HEjtmSN`?>!lvI6;>1s;*b z3=G_YAk0{w5<>&kwYU6PYkuJq01zd#|$64!_l=ltB<)VvY~=c3falGGH1 z^30M91$R&1fbd2>aiAhGkfPxHw370~qEv>0#LT=By}Z;C1rt33>la@$fhu-;x;Tb- zcyGO8$k%MZ!y0gmt5Cs>?`mUop{Ut0z8+gA_UnZiD%SfaGE`Rx{Y&8HSg5>6z~Bpm zGe3|xob;C6Y;)_|H?=a$a~f>fCAzlGztMeB{^cE(YDu1@jQpGJa$Jm8HR${F-`^FS zoy>3TE~>QO-ekek%;zhdo*Z>NtJ^(yG1tU!dDHE0%KEfi9z56(UYPnZ4XEzXpXbxo ztu0%q)m1Fb@@}7&hSRn${wMrjs7X{cEM%9s=YCf_RinJ;Y|lplpf?yiUHx3vIVCg! E06^w|-v9sr diff --git a/ui/window/minimizeButtonPressed.png b/ui/window/minimizeButtonPressed.png deleted file mode 100644 index c72c1a5e9e9f44003305e751c0321ad8140e5139..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 372 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H1|*Mc$*~4fEa{HEjtmSN`?>!lvI6;>1s;*b z3=G_YAk0{w5<>&kwYU6PYkuJq01zd#|$64!_l=ltB<)VvY~=c3falGGH1 z^30M91$R&1fbd2>aiAhGkfPxHw370~qEv>0#LT=By}Z;C1rt33>la@$fhzWRx;Tb- zcyGO8$k%MZ!+N1d)*`^2?`mUoA>+G?8<~@z`^essXIHxUvzNu<@Z=Bd(GDDn$8NCl z+FrQ83?w#09AXeYv*A#+wckyLYBLiNZ;6Mj_w6t3ocN82cWER4X1juP<5dje%Z}&Y zUHP?T_T0r>6YtAQU--14I7IQ&qYcld-8>iAdSdnYS!lvI6;>1s;*b z3=G^tAk28_ZrvZCAbW|YuPggqc1ccFxzab2{{n?1OI#yLobz*YQ}ap~oQqNuOHxx5 z$}>wc6x=<11Hv2m#DR*$K#GF%(@M${i&7a15;OBk^zu?m6ioCCtY3W11gf~{>EamT z;l1_BLSCjo0hSBG94t&iT#iB_tO0D3m_B%PIRr4MDqLV`bWjoyX>h4Y6RJC;=lpK+ zZDIXHb!%1 z1#RxLzdCcJcRfS5tVONJ>kps5{FOBpnD$J5X^?jPah{f?z1mZ6{I*V0(3u;%^2p)) zhRlg8w;qlT*DCx_e#RjpYDZA#*8RzBhlJv9+s}W@=M2;%DfU?2qs{5h j+5}T19NW$=eZ^X__v`$H9AEi>o@DTJ^>bP0l+XkK9TJb^ diff --git a/ui/window/restoreButtonHover.png b/ui/window/restoreButtonHover.png deleted file mode 100644 index dae87a3b54d0aed6bf82c99d9dffc0f48ae977c8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 401 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H1|*Mc$*~4fEa{HEjtmSN`?>!lvI6;>1s;*b z3=G^tAk28_ZrvZCAbW|YuPggqc1ccFxzab2{{n?1OI#yLobz*YQ}ap~oQqNuOHxx5 z$}>wc6x=<11Hv2m#DR*$K#GF%(@M${i&7a15;OBk^zu?m6ioCCtY3W11gf~{>EamT z;l1_BLSCjo0hRz3rbdSc8BCon3YyHGj1?-b3K|VU0wN6#b6gZO7&?EPQTaakb}GmG zJM$_yt#3vao?JdX=v51k@(F_`5HUNXn=$7B$9JiEW9e0XYR*oDY@$o_^9;gcCn<6T zS6pSUi(Dlw&nWi0AXB9N;d9BK)@celYo(S3Mb{taX<52gd#VLkC^mNGk<0fDnG;uT zKFl7jRrsy^j6+1!?x4=O`;*xY3B}*GpZ}OK8K_56?6JH@o711k=K^~E3uk$^38qLm ew!K|?PkN3I=e3&*mg|9@WbkzLb6Mw<&;$UDIf%^w diff --git a/ui/window/restoreButtonPressed.png b/ui/window/restoreButtonPressed.png deleted file mode 100644 index 719b3f8bc8cf2195d484e1ac0df1c1d64cb03a92..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 402 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H1|*Mc$*~4fEa{HEjtmSN`?>!lvI6;>1s;*b z3=G^tAk28_ZrvZCAbW|YuPggqc1ccFxzab2{{n?1OI#yLobz*YQ}ap~oQqNuOHxx5 z$}>wc6x=<11Hv2m#DR*$K#GF%(@M${i&7a15;OBk^zu?m6ioCCtY3W11gf~@>EamT z;l1_BLf%6O0;~_XgakNPnnRQ%8w@A#G`JhFG%-prUSt&DP+>aA@Fbk$m)=X&y^kmU zTN3_J_0H+N!oGD~Q!XiFNHn$yf{3h`slqo7amw-j)V(>SRD_qci+jhx=k3-yk>M8v zT7~YNZPe2)d#run5r^K|B=Mg%#`VW}n7m(yX~_>rGrz8=KPg4=Fo|a)jWP0 zER@jRzi!InPvvJ6Hf$+eDpL*C@#)sTpECY4ep{ynMD)}vaJBwWUmMW#U-(rw#2tT^ aE@I1I+Vea~Vu=UPmkge+elF{r5}E+mN|D?E diff --git a/widget/form/chatform.cpp b/widget/form/chatform.cpp index f309ce94a..a7e0a47b8 100644 --- a/widget/form/chatform.cpp +++ b/widget/form/chatform.cpp @@ -163,7 +163,7 @@ void ChatForm::onFileRecvRequest(ToxFile file) connect(Core::getInstance(), SIGNAL(fileTransferBrokenUnbroken(ToxFile, bool)), fileTrans, SLOT(onFileTransferBrokenUnbroken(ToxFile, bool))); Widget* w = Widget::getInstance(); - if (!w->isFriendWidgetCurActiveWidget(f)|| w->getIsWindowMinimized() || !w->isActiveWindow()) + if (!w->isFriendWidgetCurActiveWidget(f)|| w->isMinimized() || !w->isActiveWindow()) { w->newMessageAlert(); f->hasNewEvents=true; @@ -204,7 +204,7 @@ void ChatForm::onAvInvite(int FriendId, int CallId, bool video) } Widget* w = Widget::getInstance(); - if (!w->isFriendWidgetCurActiveWidget(f)|| w->getIsWindowMinimized() || !w->isActiveWindow()) + if (!w->isFriendWidgetCurActiveWidget(f)|| w->isMinimized() || !w->isActiveWindow()) { w->newMessageAlert(); f->hasNewEvents=true; diff --git a/widget/groupwidget.cpp b/widget/groupwidget.cpp index ab64a54da..f6538a153 100644 --- a/widget/groupwidget.cpp +++ b/widget/groupwidget.cpp @@ -77,27 +77,16 @@ void GroupWidget::updateStatusLight() { Group *g = GroupList::findGroup(groupId); - if (Settings::getInstance().getUseNativeDecoration()) + if (g->hasNewMessages == 0) { - if (g->hasNewMessages == 0) - { - statusPic.setPixmap(QPixmap(":img/status/dot_online.png")); - } else { - if (g->userWasMentioned == 0) - statusPic.setPixmap(QPixmap(":img/status/dot_online_notification.png")); - else - statusPic.setPixmap(QPixmap(":img/status/dot_online_notification.png")); - } - } else { - if (g->hasNewMessages == 0) - { - statusPic.setPixmap(QPixmap(":img/status/dot_groupchat.png")); - } else { - if (g->userWasMentioned == 0) - statusPic.setPixmap(QPixmap(":img/status/dot_groupchat_newmessages.png")); - else - statusPic.setPixmap(QPixmap(":img/status/dot_groupchat_notification.png")); - } + statusPic.setPixmap(QPixmap(":img/status/dot_groupchat.png")); + } + else + { + if (g->userWasMentioned == 0) + statusPic.setPixmap(QPixmap(":img/status/dot_groupchat_newmessages.png")); + else + statusPic.setPixmap(QPixmap(":img/status/dot_groupchat_notification.png")); } } diff --git a/widget/widget.cpp b/widget/widget.cpp index 92c1ed95b..2a83e7d8e 100644 --- a/widget/widget.cpp +++ b/widget/widget.cpp @@ -62,55 +62,8 @@ Widget::Widget(QWidget *parent) restoreState(Settings::getInstance().getWindowState()); ui->mainSplitter->restoreState(Settings::getInstance().getSplitterState()); - if (Settings::getInstance().getUseNativeDecoration()) - { - ui->titleBar->hide(); - this->layout()->setContentsMargins(0, 0, 0, 0); - - ui->friendList->setObjectName("friendList"); - ui->friendList->setStyleSheet(Style::getStylesheet(":ui/friendList/friendList.css")); - } - else - { - this->setObjectName("activeWindow"); - this->setStyleSheet(Style::getStylesheet(":ui/window/window.css")); - ui->statusPanel->setStyleSheet(QString("")); - ui->friendList->setStyleSheet(QString("")); - - ui->friendList->setObjectName("friendList"); - ui->friendList->setStyleSheet(Style::getStylesheet(":ui/friendList/friendList.css")); - - ui->tbMenu->setIcon(QIcon(":ui/window/applicationIcon.png")); - ui->pbMin->setObjectName("minimizeButton"); - ui->pbMax->setObjectName("maximizeButton"); - ui->pbClose->setObjectName("closeButton"); - - setWindowFlags(Qt::CustomizeWindowHint); - setWindowFlags(Qt::FramelessWindowHint); - - addAction(ui->actionClose); - - connect(ui->pbMin, SIGNAL(clicked()), this, SLOT(minimizeBtnClicked())); - connect(ui->pbMax, SIGNAL(clicked()), this, SLOT(maximizeBtnClicked())); - connect(ui->pbClose, SIGNAL(clicked()), this, SLOT(close())); - - m_titleMode = FullTitle; - moveWidget = false; - inResizeZone = false; - allowToResize = false; - resizeVerSup = false; - resizeHorEsq = false; - resizeDiagSupEsq = false; - resizeDiagSupDer = false; - - if (isMaximized()) - { - showMaximized(); - ui->pbMax->setObjectName("restoreButton"); - } - } - - isWindowMinimized = 0; + layout()->setContentsMargins(0, 0, 0, 0); + ui->friendList->setStyleSheet(Style::getStylesheet(":ui/friendList/friendList.css")); profilePicture = new MaskablePixmapWidget(this, QSize(40,40), ":/img/avatar_mask.png"); profilePicture->setPixmap(QPixmap(":/img/contact_dark.png")); @@ -225,8 +178,6 @@ Widget::~Widget() coreThread->terminate(); delete core; - hideMainForms(); - for (Friend* f : FriendList::friendList) delete f; FriendList::friendList.clear(); @@ -390,7 +341,7 @@ void Widget::hideMainForms() item->widget()->hide(); while ((item = ui->mainContent->layout()->takeAt(0)) != 0) item->widget()->hide(); - + if (activeChatroomWidget != nullptr) { activeChatroomWidget->setAsInactiveChatroom(); @@ -485,8 +436,8 @@ void Widget::onFriendStatusChanged(int friendId, Status status) f->widget->updateStatusLight(); // Workaround widget style after returning to list - if (f->widget->isActive()) - f->widget->setAsActiveChatroom(); +// if (f->widget->isActive()) +// f->widget->setAsActiveChatroom(); } void Widget::onFriendStatusMessageChanged(int friendId, const QString& message) @@ -535,7 +486,7 @@ void Widget::onFriendMessageReceived(int friendId, const QString& message, bool if (activeChatroomWidget != nullptr) { - if ((static_cast(f->widget) != activeChatroomWidget) || isWindowMinimized || !isActiveWindow()) + if ((static_cast(f->widget) != activeChatroomWidget) || isMinimized() || !isActiveWindow()) { f->hasNewEvents = 1; newMessageAlert(); @@ -619,7 +570,7 @@ void Widget::onGroupMessageReceived(int groupnumber, int friendgroupnumber, cons g->chatForm->addGroupMessage(message, friendgroupnumber); - if ((static_cast(g->widget) != activeChatroomWidget) || isWindowMinimized || !isActiveWindow()) + if ((static_cast(g->widget) != activeChatroomWidget) || isMinimized() || !isActiveWindow()) { g->hasNewMessages = 1; if (message.contains(core->getUsername(), Qt::CaseInsensitive)) @@ -712,368 +663,18 @@ bool Widget::isFriendWidgetCurActiveWidget(Friend* f) bool Widget::event(QEvent * e) { - - if( e->type() == QEvent::WindowStateChange ) + if (e->type() == QEvent::WindowActivate) { - if(windowState().testFlag(Qt::WindowMinimized) == true) - { - isWindowMinimized = 1; - } - } - else if (e->type() == QEvent::WindowActivate) - { - if (!Settings::getInstance().getUseNativeDecoration()) - { - this->setObjectName("activeWindow"); - this->style()->polish(this); - } - isWindowMinimized = 0; if (activeChatroomWidget != nullptr) { activeChatroomWidget->resetEventFlags(); activeChatroomWidget->updateStatusLight(); } } - else if (e->type() == QEvent::WindowDeactivate && !Settings::getInstance().getUseNativeDecoration()) - { - this->setObjectName("inactiveWindow"); - this->style()->polish(this); - } - else if (e->type() == QEvent::MouseMove && !Settings::getInstance().getUseNativeDecoration()) - { - QMouseEvent *k = (QMouseEvent *)e; - int xMouse = k->pos().x(); - int yMouse = k->pos().y(); - int wWidth = this->geometry().width(); - int wHeight = this->geometry().height(); - - if (moveWidget) - { - inResizeZone = false; - moveWindow(k); - } - else if (allowToResize) - resizeWindow(k); - else if (xMouse >= wWidth - PIXELS_TO_ACT or allowToResize) - { - inResizeZone = true; - - if (yMouse >= wHeight - PIXELS_TO_ACT) - { - setCursor(Qt::SizeFDiagCursor); - resizeWindow(k); - } - else if (yMouse <= PIXELS_TO_ACT) - { - setCursor(Qt::SizeBDiagCursor); - resizeWindow(k); - } - - } - else - { - inResizeZone = false; - setCursor(Qt::ArrowCursor); - } - - e->accept(); - } return QWidget::event(e); } -void Widget::mousePressEvent(QMouseEvent *e) -{ - if (!Settings::getInstance().getUseNativeDecoration()) - { - if (e->button() == Qt::LeftButton) - { - if (inResizeZone) - { - allowToResize = true; - - if (e->pos().y() <= PIXELS_TO_ACT) - { - if (e->pos().x() <= PIXELS_TO_ACT) - resizeDiagSupEsq = true; - else if (e->pos().x() >= geometry().width() - PIXELS_TO_ACT) - resizeDiagSupDer = true; - else - resizeVerSup = true; - } - else if (e->pos().x() <= PIXELS_TO_ACT) - resizeHorEsq = true; - } - else if (e->pos().x() >= PIXELS_TO_ACT and e->pos().x() < ui->titleBar->geometry().width() - and e->pos().y() >= PIXELS_TO_ACT and e->pos().y() < ui->titleBar->geometry().height()) - { - moveWidget = true; - dragPosition = e->globalPos() - frameGeometry().topLeft(); - } - } - - e->accept(); - } -} - -void Widget::mouseReleaseEvent(QMouseEvent *e) -{ - if (!Settings::getInstance().getUseNativeDecoration()) - { - moveWidget = false; - allowToResize = false; - resizeVerSup = false; - resizeHorEsq = false; - resizeDiagSupEsq = false; - resizeDiagSupDer = false; - - e->accept(); - } -} - -void Widget::mouseDoubleClickEvent(QMouseEvent *e) -{ - if (!Settings::getInstance().getUseNativeDecoration()) - { - if (e->pos().x() < ui->tbMenu->geometry().right() and e->pos().y() < ui->tbMenu->geometry().bottom() - and e->pos().x() >= ui->tbMenu->geometry().x() and e->pos().y() >= ui->tbMenu->geometry().y() - and ui->tbMenu->isVisible()) - close(); - else if (e->pos().x() < ui->titleBar->geometry().width() - and e->pos().y() < ui->titleBar->geometry().height() - and m_titleMode != FullScreenMode) - maximizeBtnClicked(); - e->accept(); - } -} - -void Widget::paintEvent (QPaintEvent *) -{ - QStyleOption opt; - opt.init (this); - QPainter p(this); - style()->drawPrimitive (QStyle::PE_Widget, &opt, &p, this); -} - -void Widget::moveWindow(QMouseEvent *e) -{ - if (!Settings::getInstance().getUseNativeDecoration()) - { - if (e->buttons() & Qt::LeftButton) - { - move(e->globalPos() - dragPosition); - e->accept(); - } - } -} - -void Widget::resizeWindow(QMouseEvent *e) -{ - if (!Settings::getInstance().getUseNativeDecoration()) - { - if (allowToResize) - { - int xMouse = e->pos().x(); - int yMouse = e->pos().y(); - int wWidth = geometry().width(); - int wHeight = geometry().height(); - - if (cursor().shape() == Qt::SizeVerCursor) - { - if (resizeVerSup) - { - int newY = geometry().y() + yMouse; - int newHeight = wHeight - yMouse; - - if (newHeight > minimumSizeHint().height()) - { - resize(wWidth, newHeight); - move(geometry().x(), newY); - } - } - else - resize(wWidth, yMouse+1); - } - else if (cursor().shape() == Qt::SizeHorCursor) - { - if (resizeHorEsq) - { - int newX = geometry().x() + xMouse; - int newWidth = wWidth - xMouse; - - if (newWidth > minimumSizeHint().width()) - { - resize(newWidth, wHeight); - move(newX, geometry().y()); - } - } - else - resize(xMouse, wHeight); - } - else if (cursor().shape() == Qt::SizeBDiagCursor) - { - int newX = 0; - int newWidth = 0; - int newY = 0; - int newHeight = 0; - - if (resizeDiagSupDer) - { - newX = geometry().x(); - newWidth = xMouse; - newY = geometry().y() + yMouse; - newHeight = wHeight - yMouse; - } - else - { - newX = geometry().x() + xMouse; - newWidth = wWidth - xMouse; - newY = geometry().y(); - newHeight = yMouse; - } - - if (newWidth >= minimumSizeHint().width() and newHeight >= minimumSizeHint().height()) - { - resize(newWidth, newHeight); - move(newX, newY); - } - else if (newWidth >= minimumSizeHint().width()) - { - resize(newWidth, wHeight); - move(newX, geometry().y()); - } - else if (newHeight >= minimumSizeHint().height()) - { - resize(wWidth, newHeight); - move(geometry().x(), newY); - } - } - else if (cursor().shape() == Qt::SizeFDiagCursor) - { - if (resizeDiagSupEsq) - { - int newX = geometry().x() + xMouse; - int newWidth = wWidth - xMouse; - int newY = geometry().y() + yMouse; - int newHeight = wHeight - yMouse; - - if (newWidth >= minimumSizeHint().width() and newHeight >= minimumSizeHint().height()) - { - resize(newWidth, newHeight); - move(newX, newY); - } - else if (newWidth >= minimumSizeHint().width()) - { - resize(newWidth, wHeight); - move(newX, geometry().y()); - } - else if (newHeight >= minimumSizeHint().height()) - { - resize(wWidth, newHeight); - move(geometry().x(), newY); - } - } - else - resize(xMouse+1, yMouse+1); - } - - e->accept(); - } - } -} - -void Widget::setCentralWidget(QWidget *widget, const QString &widgetName) -{ - connect(widget, SIGNAL(cancelled()), this, SLOT(close())); - - centralLayout->addWidget(widget); - //ui->centralWidget->setLayout(centralLayout); - ui->LTitle->setText(widgetName); -} - -void Widget::setTitlebarMode(const TitleMode &flag) -{ - m_titleMode = flag; - - switch (m_titleMode) - { - case CleanTitle: - ui->tbMenu->setHidden(true); - ui->pbMin->setHidden(true); - ui->pbMax->setHidden(true); - ui->pbClose->setHidden(true); - break; - case OnlyCloseButton: - ui->tbMenu->setHidden(true); - ui->pbMin->setHidden(true); - ui->pbMax->setHidden(true); - break; - case MenuOff: - ui->tbMenu->setHidden(true); - break; - case MaxMinOff: - ui->pbMin->setHidden(true); - ui->pbMax->setHidden(true); - break; - case FullScreenMode: - ui->pbMax->setHidden(true); - showMaximized(); - break; - case MaximizeModeOff: - ui->pbMax->setHidden(true); - break; - case MinimizeModeOff: - ui->pbMin->setHidden(true); - break; - case FullTitle: - ui->tbMenu->setVisible(true); - ui->pbMin->setVisible(true); - ui->pbMax->setVisible(true); - ui->pbClose->setVisible(true); - break; - break; - default: - ui->tbMenu->setVisible(true); - ui->pbMin->setVisible(true); - ui->pbMax->setVisible(true); - ui->pbClose->setVisible(true); - break; - } - ui->LTitle->setVisible(true); -} - -void Widget::setTitlebarMenu(QMenu *menu, const QString &icon) -{ - ui->tbMenu->setMenu(menu); - ui->tbMenu->setIcon(QIcon(icon)); -} - -void Widget::maximizeBtnClicked() -{ - if (isFullScreen() or isMaximized()) - { - ui->pbMax->setIcon(QIcon(":/ui/images/app_max.png")); - setWindowState(windowState() & ~Qt::WindowFullScreen & ~Qt::WindowMaximized); - } - else - { - ui->pbMax->setIcon(QIcon(":/ui/images/app_rest.png")); - setWindowState(windowState() | Qt::WindowFullScreen | Qt::WindowMaximized); - } -} - -void Widget::minimizeBtnClicked() -{ - if (isMinimized()) - { - setWindowState(windowState() & ~Qt::WindowMinimized); - } - else - { - setWindowState(windowState() | Qt::WindowMinimized); - } -} - void Widget::setStatusOnline() { core->setStatus(Status::Online); @@ -1089,21 +690,6 @@ void Widget::setStatusBusy() core->setStatus(Status::Busy); } -bool Widget::eventFilter(QObject *, QEvent *event) -{ - if (event->type() == QEvent::Wheel) - { - QWheelEvent * whlEvnt = static_cast< QWheelEvent * >( event ); - whlEvnt->angleDelta().setX(0); - } - return false; -} - -bool Widget::getIsWindowMinimized() -{ - return static_cast(isWindowMinimized); -} - void Widget::onMessageSendResult(int friendId, const QString& message, int messageId) { Q_UNUSED(message) diff --git a/widget/widget.h b/widget/widget.h index 41289c9cd..3d7858e78 100644 --- a/widget/widget.h +++ b/widget/widget.h @@ -46,9 +46,6 @@ class Widget : public QMainWindow public: explicit Widget(QWidget *parent = 0); - enum TitleMode { CleanTitle = 0, OnlyCloseButton, MenuOff, MaxMinOff, FullScreenMode, MaximizeModeOff, MinimizeModeOff, FullTitle }; - void setTitlebarMode(const TitleMode &flag); - void setTitlebarMenu(QMenu *menu, const QString &icon = ""); void setCentralWidget(QWidget *widget, const QString &widgetName); QString getUsername(); Core* getCore(); @@ -71,8 +68,6 @@ signals: void statusMessageChanged(const QString& statusMessage); private slots: - void maximizeBtnClicked(); - void minimizeBtnClicked(); void onConnected(); void onDisconnected(); void onStatusSet(Status status); @@ -108,32 +103,15 @@ private slots: void onMessageSendResult(int friendId, const QString& message, int messageId); void onGroupSendResult(int groupId, const QString& message, int result); -protected slots: - void moveWindow(QMouseEvent *e); - private: void hideMainForms(); + virtual bool event(QEvent * e); Group* createGroup(int groupId); private: Ui::MainWindow *ui; QSplitter *centralLayout; QPoint dragPosition; - TitleMode m_titleMode; - bool moveWidget; - bool inResizeZone; - bool allowToResize; - bool resizeVerSup; - bool resizeHorEsq; - bool resizeDiagSupEsq; - bool resizeDiagSupDer; - void mousePressEvent(QMouseEvent *e); - void mouseReleaseEvent(QMouseEvent *e); - void mouseDoubleClickEvent(QMouseEvent *e); - void paintEvent (QPaintEvent *); - void resizeWindow(QMouseEvent *e); - bool event(QEvent *event); - int isWindowMinimized; Core* core; QThread* coreThread; AddFriendForm friendForm; @@ -145,7 +123,6 @@ private: Camera* camera; MaskablePixmapWidget* profilePicture; bool notify(QObject *receiver, QEvent *event); - bool eventFilter(QObject *, QEvent *event); }; #endif // WIDGET_H From b93343bb99e33114f39d2effde1d0427c31b8277 Mon Sep 17 00:00:00 2001 From: krepa098 Date: Sat, 4 Oct 2014 11:02:28 +0200 Subject: [PATCH 168/205] tweak --- ui/chatArea/innerStyle.css | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ui/chatArea/innerStyle.css b/ui/chatArea/innerStyle.css index 03db4367b..823c8dfbe 100644 --- a/ui/chatArea/innerStyle.css +++ b/ui/chatArea/innerStyle.css @@ -40,7 +40,7 @@ span.quote { div.green { margin-top: 12px; margin-bottom: 12px; - margin-left: 12px; + margin-left: 0px; margin-right: 12px; color: @white; background-color: @green; @@ -50,7 +50,7 @@ div.green { div.silver { margin-top: 12px; margin-bottom: 12px; - margin-left: 12px; + margin-left: 0px; margin-right: 12px; color: @black; background-color: @lightGrey; @@ -60,7 +60,7 @@ div.silver { div.red { margin-top: 12px; margin-bottom: 12px; - margin-left: 12px; + margin-left: 0px; margin-right: 12px; color: @white; background-color: @red; From 67a7f99d71524b23d33a43128ba7b676f1bbdeca Mon Sep 17 00:00:00 2001 From: krepa098 Date: Sat, 4 Oct 2014 11:08:14 +0200 Subject: [PATCH 169/205] fixed wrong group status image --- widget/groupwidget.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/widget/groupwidget.cpp b/widget/groupwidget.cpp index f6538a153..05d04cf76 100644 --- a/widget/groupwidget.cpp +++ b/widget/groupwidget.cpp @@ -79,14 +79,14 @@ void GroupWidget::updateStatusLight() if (g->hasNewMessages == 0) { - statusPic.setPixmap(QPixmap(":img/status/dot_groupchat.png")); + statusPic.setPixmap(QPixmap(":img/status/dot_online.png")); } else { if (g->userWasMentioned == 0) - statusPic.setPixmap(QPixmap(":img/status/dot_groupchat_newmessages.png")); + statusPic.setPixmap(QPixmap(":img/status/dot_online_notification.png")); else - statusPic.setPixmap(QPixmap(":img/status/dot_groupchat_notification.png")); + statusPic.setPixmap(QPixmap(":img/status/dot_online_notification.png")); } } From ba42c934a34782d7b55d0b4993fdd3add089a1bd Mon Sep 17 00:00:00 2001 From: Zetok Zalbavar Date: Sat, 4 Oct 2014 20:40:14 +0100 Subject: [PATCH 170/205] Change indicator for action messages --- widget/tool/chatactions/actionaction.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/widget/tool/chatactions/actionaction.cpp b/widget/tool/chatactions/actionaction.cpp index 754966107..8533b7cd8 100644 --- a/widget/tool/chatactions/actionaction.cpp +++ b/widget/tool/chatactions/actionaction.cpp @@ -40,7 +40,7 @@ void ActionAction::setup(QTextCursor cursor, QTextEdit *) QString ActionAction::getName() { - return QString("
-*-
"); + return QString("
*
"); } QString ActionAction::getMessage() From 7100fb707be698e71a9e63d709ac08334c09899e Mon Sep 17 00:00:00 2001 From: krepa098 Date: Sun, 5 Oct 2014 14:22:28 +0200 Subject: [PATCH 171/205] fixed regression (#334) --- widget/friendwidget.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/widget/friendwidget.cpp b/widget/friendwidget.cpp index a524a7daf..2b830f107 100644 --- a/widget/friendwidget.cpp +++ b/widget/friendwidget.cpp @@ -149,7 +149,11 @@ void FriendWidget::onAvatarRemoved(int FriendId) return; isDefaultAvatar = true; - avatar->setPixmap(QPixmap(":img/contact.png"), Qt::transparent); + + if (isActive()) + avatar->setPixmap(QPixmap(":img/contact_dark.png"), Qt::transparent); + else + avatar->setPixmap(QPixmap(":img/contact.png"), Qt::transparent); } void FriendWidget::mousePressEvent(QMouseEvent *ev) From b487fddf994b9a87dccedd168b34296ad661e6af Mon Sep 17 00:00:00 2001 From: krepa098 Date: Sun, 5 Oct 2014 14:22:58 +0200 Subject: [PATCH 172/205] cleanup --- widget/widget.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/widget/widget.cpp b/widget/widget.cpp index 2a83e7d8e..bfe0a483a 100644 --- a/widget/widget.cpp +++ b/widget/widget.cpp @@ -434,10 +434,6 @@ void Widget::onFriendStatusChanged(int friendId, Status status) f->friendStatus = status; f->widget->updateStatusLight(); - - // Workaround widget style after returning to list -// if (f->widget->isActive()) -// f->widget->setAsActiveChatroom(); } void Widget::onFriendStatusMessageChanged(int friendId, const QString& message) From 8e664b5ff7949966e68bd9c9ad7cff9ffbcc21da Mon Sep 17 00:00:00 2001 From: krepa098 Date: Sun, 5 Oct 2014 14:36:07 +0200 Subject: [PATCH 173/205] MaskablePixmapWidget::getPixmap: return the masked pixmap --- widget/maskablepixmapwidget.cpp | 10 +++++----- widget/maskablepixmapwidget.h | 1 + 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/widget/maskablepixmapwidget.cpp b/widget/maskablepixmapwidget.cpp index 185494147..f0015d6d0 100644 --- a/widget/maskablepixmapwidget.cpp +++ b/widget/maskablepixmapwidget.cpp @@ -19,6 +19,7 @@ MaskablePixmapWidget::MaskablePixmapWidget(QWidget *parent, QSize size, QString maskName) : QWidget(parent) + , renderTarget(size) , backgroundColor(Qt::white) , clickable(false) { @@ -106,17 +107,16 @@ void MaskablePixmapWidget::setPixmap(const QPixmap &pmap) QPixmap MaskablePixmapWidget::getPixmap() const { - return pixmap; + return renderTarget; } void MaskablePixmapWidget::paintEvent(QPaintEvent *) { - QPixmap tmp(width(), height()); - tmp.fill(Qt::transparent); + renderTarget.fill(Qt::transparent); QPoint offset((width() - pixmap.size().width())/2,(height() - pixmap.size().height())/2); // centering the pixmap - QPainter painter(&tmp); + QPainter painter(&renderTarget); painter.setCompositionMode(QPainter::CompositionMode_SourceOver); painter.fillRect(0,0,width(),height(),backgroundColor); painter.drawPixmap(offset,pixmap); @@ -125,7 +125,7 @@ void MaskablePixmapWidget::paintEvent(QPaintEvent *) painter.end(); painter.begin(this); - painter.drawPixmap(0,0,tmp); + painter.drawPixmap(0,0,renderTarget); } void MaskablePixmapWidget::mousePressEvent(QMouseEvent*) diff --git a/widget/maskablepixmapwidget.h b/widget/maskablepixmapwidget.h index 2fe92c180..86e690aae 100644 --- a/widget/maskablepixmapwidget.h +++ b/widget/maskablepixmapwidget.h @@ -42,6 +42,7 @@ protected: private: QPixmap pixmap; QPixmap mask; + QPixmap renderTarget; QSize size; QString maskName; QColor backgroundColor; From 77d7189d665c0de0754e148e677053f07f885ae3 Mon Sep 17 00:00:00 2001 From: krepa098 Date: Sun, 5 Oct 2014 14:47:22 +0200 Subject: [PATCH 174/205] FileTransferInstance: use correct fontmetrics --- filetransferinstance.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/filetransferinstance.cpp b/filetransferinstance.cpp index 22570aa53..f3301e58a 100644 --- a/filetransferinstance.cpp +++ b/filetransferinstance.cpp @@ -16,6 +16,7 @@ #include "filetransferinstance.h" #include "core.h" +#include "misc/style.h" #include #include #include @@ -38,9 +39,10 @@ FileTransferInstance::FileTransferInstance(ToxFile File) lastUpdateTime = QDateTime::currentDateTime(); filename = File.fileName; - QFont font; - font.setPixelSize(10); - QFontMetrics fm(font); + + // update this whenever you change the font in innerStyle.css + QFontMetrics fm(Style::getFont(Style::Small)); + filenameElided = fm.elidedText(filename, Qt::ElideRight, CONTENT_WIDTH); size = getHumanReadableSize(File.filesize); From b5801f1800f70a81c510cd489a3ed3ff21268e04 Mon Sep 17 00:00:00 2001 From: krepa098 Date: Sun, 5 Oct 2014 14:58:47 +0200 Subject: [PATCH 175/205] Style: tweaked weight --- misc/style.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/style.cpp b/misc/style.cpp index 120991f65..1c83f0c6e 100644 --- a/misc/style.cpp +++ b/misc/style.cpp @@ -36,7 +36,7 @@ QFont appFont(int pixelSize, int weight) QString qssifyFont(QFont font) { return QString("%1 %2px \"%3\"") - .arg(font.weight()*10) + .arg(font.weight()*8) .arg(font.pixelSize()) .arg(font.family()); } From 51f24115d71dd64577165f4d8b3f1bd112624a24 Mon Sep 17 00:00:00 2001 From: krepa098 Date: Sun, 5 Oct 2014 17:34:34 +0200 Subject: [PATCH 176/205] GenericChatForm: use correct fontmetrics --- widget/form/genericchatform.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/widget/form/genericchatform.cpp b/widget/form/genericchatform.cpp index 8c3753b0b..4a73d3938 100644 --- a/widget/form/genericchatform.cpp +++ b/widget/form/genericchatform.cpp @@ -228,9 +228,8 @@ void GenericChatForm::addSystemInfoMessage(const QString &message, const QString QString GenericChatForm::getElidedName(const QString& name) { - QFont font; - font.setBold(true); - QFontMetrics fm(font); + // update this whenever you change the font in innerStyle.css + QFontMetrics fm(Style::getFont(Style::BigBold)); return fm.elidedText(name, Qt::ElideRight, chatWidget->nameColWidth()); } From 8fa9457305d55a21ddd034dc569c0053162cd31f Mon Sep 17 00:00:00 2001 From: apprb Date: Mon, 6 Oct 2014 01:17:01 +0900 Subject: [PATCH 177/205] base refactoring --- qtox.pro | 5 +- widget/form/settings/avform.cpp | 28 ++-- widget/form/settings/avform.h | 11 +- widget/form/settings/avsettings.ui | 50 ++++++ widget/form/settings/generalform.cpp | 52 +++--- widget/form/settings/generalform.h | 8 +- widget/form/settings/genericsettings.h | 33 ++-- widget/form/settings/identityform.cpp | 61 +++---- widget/form/settings/identityform.h | 15 +- widget/form/settings/privacyform.cpp | 5 +- widget/form/settingswidget.cpp | 216 +++---------------------- widget/form/settingswidget.h | 37 +---- widget/widget.cpp | 8 +- 13 files changed, 181 insertions(+), 348 deletions(-) create mode 100644 widget/form/settings/avsettings.ui diff --git a/qtox.pro b/qtox.pro index 68ab4db73..11dec4a7c 100644 --- a/qtox.pro +++ b/qtox.pro @@ -26,7 +26,10 @@ greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = qtox TEMPLATE = app FORMS += \ - mainwindow.ui + mainwindow.ui \ + widget/form/settings/generalsettings.ui \ + widget/form/settings/avsettings.ui \ + widget/form/settings/identitysettings.ui CONFIG += c++11 TRANSLATIONS = translations/de.ts \ diff --git a/widget/form/settings/avform.cpp b/widget/form/settings/avform.cpp index 3a4c86f0a..4b7afef25 100644 --- a/widget/form/settings/avform.cpp +++ b/widget/form/settings/avform.cpp @@ -16,41 +16,35 @@ #include "avform.h" #include "widget/camera.h" +#include "ui_avsettings.h" -AVForm::AVForm(Camera* cam) +AVForm::AVForm(Camera* cam) : + GenericForm(tr("Audio/Video settings"), QPixmap(":/img/settings/av.png")) { - icon.setPixmap(QPixmap(":/img/settings/av.png").scaledToHeight(headLayout.sizeHint().height(), Qt::SmoothTransformation)); - label.setText(tr("Audio/Video settings")); - - QGroupBox *group = new QGroupBox(tr("Video Settings")); + bodyUI = new Ui::AVSettings; + bodyUI->setupUi(this); - camView = new SelfCamView(cam); + camView = new SelfCamView(cam, this); + bodyUI->videoGroup->layout()->addWidget(camView); camView->hide(); // hide by default - testVideo = new QPushButton(tr("Show video preview","On a button")); - connect(testVideo, &QPushButton::clicked, this, &AVForm::onTestVideoPressed); - videoLayout = new QVBoxLayout(); - videoLayout->addWidget(testVideo); - videoLayout->addWidget(camView); - //videoGroup->setLayout(videoLayout); // strangely enough, this causes a segfault.... - - layout.addWidget(group); - layout.addStretch(1); + connect(bodyUI->testVideoBtn, &QPushButton::clicked, this, &AVForm::onTestVideoPressed); } AVForm::~AVForm() { + delete bodyUI; } void AVForm::showTestVideo() { - testVideo->setText(tr("Hide video preview","On a button")); + bodyUI->testVideoBtn->setText(tr("Hide video preview","On a button")); camView->show(); } void AVForm::closeTestVideo() { - testVideo->setText(tr("Show video preview","On a button")); + bodyUI->testVideoBtn->setText(tr("Show video preview","On a button")); camView->close(); } diff --git a/widget/form/settings/avform.h b/widget/form/settings/avform.h index be7c97dae..e75f742da 100644 --- a/widget/form/settings/avform.h +++ b/widget/form/settings/avform.h @@ -22,6 +22,11 @@ #include #include #include + +namespace Ui { +class AVSettings; +} + class Camera; class AVForm : public GenericForm @@ -33,10 +38,10 @@ public: private slots: void onTestVideoPressed(); + private: - QGroupBox* videoGroup; - QVBoxLayout* videoLayout; - QPushButton* testVideo; + Ui::AVSettings *bodyUI; + SelfCamView* camView; void showTestVideo(); diff --git a/widget/form/settings/avsettings.ui b/widget/form/settings/avsettings.ui new file mode 100644 index 000000000..77fbb18b4 --- /dev/null +++ b/widget/form/settings/avsettings.ui @@ -0,0 +1,50 @@ + + + AVSettings + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + + Video settings + + + + + + Show video preview + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + diff --git a/widget/form/settings/generalform.cpp b/widget/form/settings/generalform.cpp index 1c7ed8bff..c816f4225 100644 --- a/widget/form/settings/generalform.cpp +++ b/widget/form/settings/generalform.cpp @@ -14,65 +14,57 @@ See the COPYING file for more details. */ +#include "ui_generalsettings.h" #include "generalform.h" #include "widget/form/settingswidget.h" #include "widget/widget.h" #include "misc/settings.h" #include "misc/smileypack.h" -GeneralForm::GeneralForm() +GeneralForm::GeneralForm() : + GenericForm(tr("General Settings"), QPixmap(":/img/settings/general.png")) { - icon.setPixmap(QPixmap(":/img/settings/general.png").scaledToHeight(headLayout.sizeHint().height(), Qt::SmoothTransformation)); - label.setText(tr("General Settings")); - - enableIPv6.setText(tr("Enable IPv6 (recommended)","Text on a checkbox to enable IPv6")); - enableIPv6.setChecked(Settings::getInstance().getEnableIPv6()); - useTranslations.setText(tr("Use translations","Text on a checkbox to enable translations")); - useTranslations.setChecked(Settings::getInstance().getUseTranslations()); - makeToxPortable.setText(tr("Make Tox portable","Text on a checkbox to make qTox a portable application")); - makeToxPortable.setChecked(Settings::getInstance().getMakeToxPortable()); - makeToxPortable.setToolTip(tr("Save settings to the working directory instead of the usual conf dir","describes makeToxPortable checkbox")); + bodyUI = new Ui::GeneralSettings; + bodyUI->setupUi(this); + + bodyUI->cbEnableIPv6->setChecked(Settings::getInstance().getEnableIPv6()); + bodyUI->cbUseTranslations->setChecked(Settings::getInstance().getUseTranslations()); + bodyUI->cbMakeToxPortable->setChecked(Settings::getInstance().getMakeToxPortable()); - smileyPackLabel.setText(tr("Smiley Pack", "Text on smiley pack label")); for (auto entry : SmileyPack::listSmileyPacks()) - smileyPackBrowser.addItem(entry.first, entry.second); - smileyPackBrowser.setCurrentIndex(smileyPackBrowser.findData(Settings::getInstance().getSmileyPack())); + { + bodyUI->smileyPackBrowser->addItem(entry.first, entry.second); + } + bodyUI->smileyPackBrowser->setCurrentIndex(bodyUI->smileyPackBrowser->findData(Settings::getInstance().getSmileyPack())); - headLayout.addWidget(&label); - layout.addWidget(&enableIPv6); - layout.addWidget(&useTranslations); - layout.addWidget(&makeToxPortable); - layout.addWidget(&smileyPackLabel); - layout.addWidget(&smileyPackBrowser); - layout.addStretch(); - - connect(&enableIPv6, SIGNAL(stateChanged(int)), this, SLOT(onEnableIPv6Updated())); - connect(&useTranslations, SIGNAL(stateChanged(int)), this, SLOT(onUseTranslationUpdated())); - connect(&makeToxPortable, SIGNAL(stateChanged(int)), this, SLOT(onMakeToxPortableUpdated())); - connect(&smileyPackBrowser, SIGNAL(currentIndexChanged(int)), this, SLOT(onSmileyBrowserIndexChanged(int))); + connect(bodyUI->cbEnableIPv6, SIGNAL(stateChanged(int)), this, SLOT(onEnableIPv6Updated())); + connect(bodyUI->cbUseTranslations, SIGNAL(stateChanged(int)), this, SLOT(onUseTranslationUpdated())); + connect(bodyUI->cbMakeToxPortable, SIGNAL(stateChanged(int)), this, SLOT(onMakeToxPortableUpdated())); + connect(bodyUI->smileyPackBrowser, SIGNAL(currentIndexChanged(int)), this, SLOT(onSmileyBrowserIndexChanged(int))); } GeneralForm::~GeneralForm() { + delete bodyUI; } void GeneralForm::onEnableIPv6Updated() { - Settings::getInstance().setEnableIPv6(enableIPv6.isChecked()); + Settings::getInstance().setEnableIPv6(bodyUI->cbEnableIPv6->isChecked()); } void GeneralForm::onUseTranslationUpdated() { - Settings::getInstance().setUseTranslations(useTranslations.isChecked()); + Settings::getInstance().setUseTranslations(bodyUI->cbUseTranslations->isChecked()); } void GeneralForm::onMakeToxPortableUpdated() { - Settings::getInstance().setMakeToxPortable(makeToxPortable.isChecked()); + Settings::getInstance().setMakeToxPortable(bodyUI->cbMakeToxPortable->isChecked()); } void GeneralForm::onSmileyBrowserIndexChanged(int index) { - QString filename = smileyPackBrowser.itemData(index).toString(); + QString filename = bodyUI->smileyPackBrowser->itemData(index).toString(); Settings::getInstance().setSmileyPack(filename); } diff --git a/widget/form/settings/generalform.h b/widget/form/settings/generalform.h index b33b7ffcb..5d5fd6efe 100644 --- a/widget/form/settings/generalform.h +++ b/widget/form/settings/generalform.h @@ -21,6 +21,10 @@ #include #include +namespace Ui { +class GeneralSettings; +} + class GeneralForm : public GenericForm { Q_OBJECT @@ -35,9 +39,7 @@ private slots: void onSmileyBrowserIndexChanged(int index); private: - QCheckBox enableIPv6, useTranslations, makeToxPortable; - QLabel label, smileyPackLabel; - QComboBox smileyPackBrowser; + Ui::GeneralSettings *bodyUI; }; #endif diff --git a/widget/form/settings/genericsettings.h b/widget/form/settings/genericsettings.h index 8d6d4e9bb..e3852ee28 100644 --- a/widget/form/settings/genericsettings.h +++ b/widget/form/settings/genericsettings.h @@ -17,37 +17,30 @@ #ifndef GENERICFORM_H #define GENERICFORM_H -#include -#include -#include +#include #include "widget/form/settingswidget.h" -class GenericForm : public QObject +class GenericForm : public QWidget { Q_OBJECT public: - GenericForm() - { - head.setLayout(&headLayout); - headLayout.addWidget(&icon); - headLayout.addWidget(&label); - body.setLayout(&layout); - } - ~GenericForm() {}; + GenericForm(const QString &name, const QPixmap &icon) : formName(name), formIcon(icon) {;} + ~GenericForm() {;} virtual void show(SettingsWidget& sw) { - sw.body->layout()->addWidget(&body); - body.show(); - sw.head->layout()->addWidget(&head); - head.show(); +// sw.body->layout()->addWidget(&body); +// body.show(); +// sw.head->layout()->addWidget(&head); +// head.show(); } + QString getFormName() {return formName;} + QPixmap getFormIcon() {return formIcon;} + protected: - QVBoxLayout layout; - QHBoxLayout headLayout; - QLabel label, icon; - QWidget head, body; + QString formName; + QPixmap formIcon; }; #endif diff --git a/widget/form/settings/identityform.cpp b/widget/form/settings/identityform.cpp index 57a69a759..bfc231c33 100644 --- a/widget/form/settings/identityform.cpp +++ b/widget/form/settings/identityform.cpp @@ -14,6 +14,7 @@ See the COPYING file for more details. */ +#include "ui_identitysettings.h" #include "identityform.h" #include "widget/form/settingswidget.h" #include "widget/croppinglabel.h" @@ -23,34 +24,18 @@ #include #include -IdentityForm::IdentityForm() +IdentityForm::IdentityForm() : + GenericForm(tr("Your identity"), QPixmap(":/img/settings/identity.png")) { - icon.setPixmap(QPixmap(":/img/settings/identity.png").scaledToHeight(headLayout.sizeHint().height(), Qt::SmoothTransformation)); - label.setText(tr("Your identity")); + bodyUI = new Ui::IdentitySettings; + bodyUI->setupUi(this); - // public - publicGroup = new QGroupBox(tr("Public Information")); - userNameLabel = new QLabel(tr("Name","Username/nick")); - userName = new QLineEdit(); - - statusMessageLabel = new QLabel(tr("Status","Status message")); - statusMessage = new QLineEdit(); - - vLayout = new QVBoxLayout(); - vLayout->addWidget(userNameLabel); - vLayout->addWidget(userName); - vLayout->addWidget(statusMessageLabel); - vLayout->addWidget(statusMessage); - publicGroup->setLayout(vLayout); - // tox - toxGroup = new QGroupBox(tr("Tox ID")); - toxIdLabel = new CroppingLabel(); - toxIdLabel->setText(tr("Your Tox ID (click to copy)")); toxId = new ClickableTE(); QFont small; small.setPixelSize(13); small.setKerning(false); + toxId->setTextInteractionFlags(Qt::TextSelectableByMouse); toxId->setReadOnly(true); toxId->setFrameStyle(QFrame::NoFrame); @@ -58,20 +43,12 @@ IdentityForm::IdentityForm() toxId->setFixedHeight(toxId->document()->size().height()*2); toxId->setFont(small); - QVBoxLayout* toxLayout = new QVBoxLayout(); - toxLayout->addWidget(toxIdLabel); - toxLayout->addWidget(toxId); - toxGroup->setLayout(toxLayout); + bodyUI->toxGroup->layout()->addWidget(toxId); - layout.setSpacing(30); - layout.addWidget(publicGroup); - layout.addWidget(toxGroup); - layout.addStretch(1); - - connect(toxIdLabel, SIGNAL(clicked()), this, SLOT(copyIdClicked())); + connect(bodyUI->toxIdLabel, SIGNAL(clicked()), this, SLOT(copyIdClicked())); connect(toxId, SIGNAL(clicked()), this, SLOT(copyIdClicked())); - connect(userName, SIGNAL(editingFinished()), this, SLOT(onUserNameEdited())); - connect(statusMessage, SIGNAL(editingFinished()), this, SLOT(onStatusMessageEdited())); + connect(bodyUI->userName, SIGNAL(editingFinished()), this, SLOT(onUserNameEdited())); + connect(bodyUI->statusMessage, SIGNAL(editingFinished()), this, SLOT(onStatusMessageEdited())); } IdentityForm::~IdentityForm() @@ -88,18 +65,28 @@ void IdentityForm::copyIdClicked() void IdentityForm::onUserNameEdited() { - emit userNameChanged(userName->text()); + emit userNameChanged(bodyUI->userName->text()); } void IdentityForm::onStatusMessageEdited() { - emit statusMessageChanged(statusMessage->text()); + emit statusMessageChanged(bodyUI->statusMessage->text()); } void IdentityForm::show(SettingsWidget& sw) { - userName->setText(Core::getInstance()->getUsername()); - statusMessage->setText(Core::getInstance()->getStatusMessage()); + bodyUI->userName->setText(Core::getInstance()->getUsername()); + bodyUI->statusMessage->setText(Core::getInstance()->getStatusMessage()); toxId->setText(Core::getInstance()->getSelfId().toString()); GenericForm::show(sw); } + +void IdentityForm::setUserName(const QString &name) +{ + bodyUI->userName->setText(name); +} + +void IdentityForm::setStatusMessage(const QString &msg) +{ + bodyUI->statusMessage->setText(msg); +} diff --git a/widget/form/settings/identityform.h b/widget/form/settings/identityform.h index 8e80e0aaf..0cacb4dc7 100644 --- a/widget/form/settings/identityform.h +++ b/widget/form/settings/identityform.h @@ -21,8 +21,14 @@ #include #include #include +#include + class CroppingLabel; +namespace Ui { +class IdentitySettings; +} + class ClickableTE : public QTextEdit { Q_OBJECT @@ -41,7 +47,8 @@ public: IdentityForm(); ~IdentityForm(); - QLineEdit* userName, * statusMessage; + void setUserName(const QString &name); + void setStatusMessage(const QString &msg); void show(SettingsWidget& sw); @@ -55,11 +62,9 @@ private slots: void onStatusMessageEdited(); private: - QGroupBox* toxGroup, * publicGroup; + Ui::IdentitySettings* bodyUI; + ClickableTE* toxId; - QLabel* userNameLabel, * statusMessageLabel; - CroppingLabel* toxIdLabel; - QVBoxLayout* vLayout, * toxLayout; }; #endif diff --git a/widget/form/settings/privacyform.cpp b/widget/form/settings/privacyform.cpp index 683bdff4b..c51dc0878 100644 --- a/widget/form/settings/privacyform.cpp +++ b/widget/form/settings/privacyform.cpp @@ -17,10 +17,9 @@ #include "privacyform.h" #include "widget/form/settingswidget.h" -PrivacyForm::PrivacyForm() +PrivacyForm::PrivacyForm() : + GenericForm(tr("Privacy settings"), QPixmap(":/img/settings/privacy.png")) { - icon.setPixmap(QPixmap(":/img/settings/privacy.png").scaledToHeight(headLayout.sizeHint().height(), Qt::SmoothTransformation)); - label.setText(tr("Privacy settings")); } PrivacyForm::~PrivacyForm() diff --git a/widget/form/settingswidget.cpp b/widget/form/settingswidget.cpp index f82e1a689..047c5aaac 100644 --- a/widget/form/settingswidget.cpp +++ b/widget/form/settingswidget.cpp @@ -22,37 +22,30 @@ #include "widget/form/settings/identityform.h" #include "widget/form/settings/privacyform.h" #include "widget/form/settings/avform.h" +#include -SettingsWidget::SettingsWidget(Camera* cam) - : QWidget() +SettingsWidget::SettingsWidget(Camera* cam, QWidget* parent) + : QWidget(parent) { - generalForm = new GeneralForm(); - identityForm = new IdentityForm(); - privacyForm = new PrivacyForm(); - avForm = new AVForm(cam); - - main = new QWidget(); body = new QWidget(); head = new QWidget(); - foot = new QWidget(); - - head->setLayout(new QVBoxLayout()); - body->setLayout(new QVBoxLayout()); - - prepButtons(); - foot->setLayout(iconsLayout); - mainLayout = new QVBoxLayout(); - mainLayout->addWidget(body); - mainLayout->addWidget(foot); - // something something foot size - main->setLayout(mainLayout); - - connect(generalButton, &QPushButton::clicked, this, &SettingsWidget::onGeneralClicked); - connect(identityButton, &QPushButton::clicked, this, &SettingsWidget::onIdentityClicked); - connect(privacyButton, &QPushButton::clicked, this, &SettingsWidget::onPrivacyClicked); - connect(avButton, &QPushButton::clicked, this, &SettingsWidget::onAVClicked); - - active = generalForm; + + QVBoxLayout *bodyLayout = new QVBoxLayout(); + body->setLayout(bodyLayout); + + QTabWidget *settingsTabs = new QTabWidget(); + bodyLayout->addWidget(settingsTabs); + + GeneralForm *gfrm = new GeneralForm; + ifrm = new IdentityForm; + PrivacyForm *pfrm = new PrivacyForm; + AVForm *avfrm = new AVForm(cam); + + GenericForm *cfgForms[] = {gfrm, ifrm, pfrm, avfrm}; + for (auto cfgForm : cfgForms) + { + settingsTabs->addTab(cfgForm, cfgForm->getFormIcon(), cfgForm->getFormName()); + } } SettingsWidget::~SettingsWidget() @@ -61,173 +54,8 @@ SettingsWidget::~SettingsWidget() void SettingsWidget::show(Ui::MainWindow& ui) { - active->show(*this); - ui.mainContent->layout()->addWidget(main); + ui.mainContent->layout()->addWidget(body); ui.mainHead->layout()->addWidget(head); - main->show(); + body->show(); head->show(); } - -void SettingsWidget::onGeneralClicked() -{ - hideSettingsForms(); - active = generalForm; - generalForm->show(*this); -} - -void SettingsWidget::onIdentityClicked() -{ - hideSettingsForms(); - active = identityForm; - identityForm->show(*this); -} - -void SettingsWidget::onPrivacyClicked() -{ - hideSettingsForms(); - active = privacyForm; - privacyForm->show(*this); -} - -void SettingsWidget::onAVClicked() -{ - hideSettingsForms(); - active = avForm; - avForm->show(*this); -} - -void SettingsWidget::hideSettingsForms() -{ - QLayoutItem *item; - while ((item = head->layout()->takeAt(0)) != 0) - item->widget()->hide(); - while ((item = body->layout()->takeAt(0)) != 0) - item->widget()->hide(); -} - -void SettingsWidget::prepButtons() -{ - // this crap is copied from ui_mainwindow.h... there's no easy way around - // just straight up copying it like this... oh well - // the layout/icons obviously need to be improved, but it's a working model, - // not a pretty one - QSizePolicy sizePolicy3(QSizePolicy::Fixed, QSizePolicy::Fixed); - sizePolicy3.setHorizontalStretch(0); - sizePolicy3.setVerticalStretch(0); - foot->setObjectName(QStringLiteral("foot")); - foot->setEnabled(true); - foot->setSizePolicy(sizePolicy3); - QPalette palette5; - QBrush brush(QColor(255, 255, 255, 255)); - brush.setStyle(Qt::SolidPattern); - QBrush brush1(QColor(28, 28, 28, 255)); - brush1.setStyle(Qt::SolidPattern); - QBrush brush2(QColor(42, 42, 42, 255)); - brush2.setStyle(Qt::SolidPattern); - QBrush brush3(QColor(35, 35, 35, 255)); - brush3.setStyle(Qt::SolidPattern); - QBrush brush4(QColor(14, 14, 14, 255)); - brush4.setStyle(Qt::SolidPattern); - QBrush brush5(QColor(18, 18, 18, 255)); - brush5.setStyle(Qt::SolidPattern); - QBrush brush6(QColor(0, 0, 0, 255)); - brush6.setStyle(Qt::SolidPattern); - QBrush brush7(QColor(255, 255, 220, 255)); - brush7.setStyle(Qt::SolidPattern); - palette5.setBrush(QPalette::Active, QPalette::WindowText, brush); - palette5.setBrush(QPalette::Active, QPalette::Button, brush1); - palette5.setBrush(QPalette::Active, QPalette::Light, brush2); - palette5.setBrush(QPalette::Active, QPalette::Midlight, brush3); - palette5.setBrush(QPalette::Active, QPalette::Dark, brush4); - palette5.setBrush(QPalette::Active, QPalette::Mid, brush5); - palette5.setBrush(QPalette::Active, QPalette::Text, brush); - palette5.setBrush(QPalette::Active, QPalette::BrightText, brush); - palette5.setBrush(QPalette::Active, QPalette::ButtonText, brush); - palette5.setBrush(QPalette::Active, QPalette::Base, brush6); - palette5.setBrush(QPalette::Active, QPalette::Window, brush1); - palette5.setBrush(QPalette::Active, QPalette::Shadow, brush6); - palette5.setBrush(QPalette::Active, QPalette::AlternateBase, brush4); - palette5.setBrush(QPalette::Active, QPalette::ToolTipBase, brush7); - palette5.setBrush(QPalette::Active, QPalette::ToolTipText, brush6); - palette5.setBrush(QPalette::Inactive, QPalette::WindowText, brush); - palette5.setBrush(QPalette::Inactive, QPalette::Button, brush1); - palette5.setBrush(QPalette::Inactive, QPalette::Light, brush2); - palette5.setBrush(QPalette::Inactive, QPalette::Midlight, brush3); - palette5.setBrush(QPalette::Inactive, QPalette::Dark, brush4); - palette5.setBrush(QPalette::Inactive, QPalette::Mid, brush5); - palette5.setBrush(QPalette::Inactive, QPalette::Text, brush); - palette5.setBrush(QPalette::Inactive, QPalette::BrightText, brush); - palette5.setBrush(QPalette::Inactive, QPalette::ButtonText, brush); - palette5.setBrush(QPalette::Inactive, QPalette::Base, brush6); - palette5.setBrush(QPalette::Inactive, QPalette::Window, brush1); - palette5.setBrush(QPalette::Inactive, QPalette::Shadow, brush6); - palette5.setBrush(QPalette::Inactive, QPalette::AlternateBase, brush4); - palette5.setBrush(QPalette::Inactive, QPalette::ToolTipBase, brush7); - palette5.setBrush(QPalette::Inactive, QPalette::ToolTipText, brush6); - palette5.setBrush(QPalette::Disabled, QPalette::WindowText, brush4); - palette5.setBrush(QPalette::Disabled, QPalette::Button, brush1); - palette5.setBrush(QPalette::Disabled, QPalette::Light, brush2); - palette5.setBrush(QPalette::Disabled, QPalette::Midlight, brush3); - palette5.setBrush(QPalette::Disabled, QPalette::Dark, brush4); - palette5.setBrush(QPalette::Disabled, QPalette::Mid, brush5); - palette5.setBrush(QPalette::Disabled, QPalette::Text, brush4); - palette5.setBrush(QPalette::Disabled, QPalette::BrightText, brush); - palette5.setBrush(QPalette::Disabled, QPalette::ButtonText, brush4); - palette5.setBrush(QPalette::Disabled, QPalette::Base, brush1); - palette5.setBrush(QPalette::Disabled, QPalette::Window, brush1); - palette5.setBrush(QPalette::Disabled, QPalette::Shadow, brush6); - palette5.setBrush(QPalette::Disabled, QPalette::AlternateBase, brush1); - palette5.setBrush(QPalette::Disabled, QPalette::ToolTipBase, brush7); - palette5.setBrush(QPalette::Disabled, QPalette::ToolTipText, brush6); - foot->setPalette(palette5); - foot->setAutoFillBackground(true); - - iconsLayout = new QHBoxLayout(foot); - iconsLayout->setSpacing(0); - iconsLayout->setObjectName(QStringLiteral("iconsLayout")); - iconsLayout->setContentsMargins(0, 0, 0, 0); - - generalButton = new QPushButton(foot); - generalButton->setObjectName(QStringLiteral("generalButton")); - generalButton->setMinimumSize(QSize(55, 35)); - generalButton->setMaximumSize(QSize(55, 35)); - generalButton->setFocusPolicy(Qt::NoFocus); - QIcon icon1; - icon1.addFile(QStringLiteral(":/img/add.png"), QSize(), QIcon::Normal, QIcon::Off); - generalButton->setIcon(icon1); - generalButton->setFlat(true); - iconsLayout->addWidget(generalButton); - - identityButton = new QPushButton(foot); - identityButton->setObjectName(QStringLiteral("identityButton")); - identityButton->setMinimumSize(QSize(55, 35)); - identityButton->setMaximumSize(QSize(55, 35)); - identityButton->setFocusPolicy(Qt::NoFocus); - QIcon icon2; - icon2.addFile(QStringLiteral(":/img/group.png"), QSize(), QIcon::Normal, QIcon::Off); - identityButton->setIcon(icon2); - identityButton->setFlat(true); - iconsLayout->addWidget(identityButton); - - privacyButton = new QPushButton(foot); - privacyButton->setObjectName(QStringLiteral("privacyButton")); - privacyButton->setMinimumSize(QSize(55, 35)); - privacyButton->setMaximumSize(QSize(55, 35)); - privacyButton->setFocusPolicy(Qt::NoFocus); - QIcon icon3; - icon3.addFile(QStringLiteral(":/img/transfer.png"), QSize(), QIcon::Normal, QIcon::Off); - privacyButton->setIcon(icon3); - privacyButton->setFlat(true); - iconsLayout->addWidget(privacyButton); - - avButton = new QPushButton(foot); - avButton->setObjectName(QStringLiteral("avButton")); - avButton->setMinimumSize(QSize(55, 35)); - avButton->setMaximumSize(QSize(55, 35)); - avButton->setFocusPolicy(Qt::NoFocus); - QIcon icon4; - icon4.addFile(QStringLiteral(":/img/settings.png"), QSize(), QIcon::Normal, QIcon::Off); - avButton->setIcon(icon4); - avButton->setFlat(true); - iconsLayout->addWidget(avButton); -} diff --git a/widget/form/settingswidget.h b/widget/form/settingswidget.h index b24f7ffb6..552af5104 100644 --- a/widget/form/settingswidget.h +++ b/widget/form/settingswidget.h @@ -25,47 +25,22 @@ class GeneralForm; class IdentityForm; class PrivacyForm; class AVForm; -namespace Ui {class MainWindow;}; + +namespace Ui {class MainWindow;} class SettingsWidget : public QWidget { Q_OBJECT public: - SettingsWidget(Camera* cam); + SettingsWidget(Camera* cam, QWidget* parent = nullptr); ~SettingsWidget(); void show(Ui::MainWindow &ui); - - QWidget *head, *body; // keep the others private - GenericForm* active; - GeneralForm* generalForm; - IdentityForm* identityForm; - PrivacyForm* privacyForm; - AVForm* avForm; - -public slots: - //void setFriendAddress(const QString& friendAddress); - -private slots: - void onGeneralClicked(); - void onIdentityClicked(); - void onPrivacyClicked(); - void onAVClicked(); + IdentityForm *getIdentityForm() {return ifrm;} private: - QWidget *main, *foot; - // main consists of body+foot for Ui::MainWindow - QVBoxLayout *mainLayout; - - void hideSettingsForms(); - - // the code pertaining to the icons is mostly copied from ui_mainwindow.h - QHBoxLayout *iconsLayout; - QPushButton *generalButton; - QPushButton *identityButton; - QPushButton *privacyButton; - QPushButton *avButton; - void prepButtons(); // just so I can move the crap to the bottom of the file + QWidget *head, *body; // keep the others private + IdentityForm *ifrm; }; #endif // SETTINGSWIDGET_H diff --git a/widget/widget.cpp b/widget/widget.cpp index a6730ec44..46e3e5d09 100644 --- a/widget/widget.cpp +++ b/widget/widget.cpp @@ -218,9 +218,9 @@ Widget::Widget(QWidget *parent) connect(ui->nameLabel, SIGNAL(textChanged(QString,QString)), this, SLOT(onUsernameChanged(QString,QString))); connect(ui->statusLabel, SIGNAL(textChanged(QString,QString)), this, SLOT(onStatusMessageChanged(QString,QString))); connect(profilePicture, SIGNAL(clicked()), this, SLOT(onAvatarClicked())); - connect(settingsWidget->identityForm, &IdentityForm::userNameChanged, core, &Core::setUsername); - connect(settingsWidget->identityForm, &IdentityForm::statusMessageChanged, core, &Core::setStatusMessage); connect(setStatusOnline, SIGNAL(triggered()), this, SLOT(setStatusOnline())); +// connect(settingsWidget->getIdentityForm(), &IdentityForm::userNameChanged, Core::getInstance(), &Core::setUsername); +// connect(settingsWidget->getIdentityForm(), &IdentityForm::statusMessageChanged, Core::getInstance(), &Core::setStatusMessage); connect(setStatusAway, SIGNAL(triggered()), this, SLOT(setStatusAway())); connect(setStatusBusy, SIGNAL(triggered()), this, SLOT(setStatusBusy())); connect(&friendForm, SIGNAL(friendRequested(QString,QString)), this, SIGNAL(friendRequested(QString,QString))); @@ -428,7 +428,7 @@ void Widget::setUsername(const QString& username) { ui->nameLabel->setText(username); ui->nameLabel->setToolTip(username); // for overlength names - settingsWidget->identityForm->userName->setText(username); + settingsWidget->getIdentityForm()->setUserName(username); } void Widget::onStatusMessageChanged(const QString& newStatusMessage, const QString& oldStatusMessage) @@ -442,7 +442,7 @@ void Widget::setStatusMessage(const QString &statusMessage) { ui->statusLabel->setText(statusMessage); ui->statusLabel->setToolTip(statusMessage); // for overlength messsages - settingsWidget->identityForm->statusMessage->setText(statusMessage); + settingsWidget->getIdentityForm()->setStatusMessage(statusMessage); } void Widget::addFriend(int friendId, const QString &userId) From 0c2bf63b1aaf0294b7777e7ad78a76a43298f236 Mon Sep 17 00:00:00 2001 From: apprb Date: Mon, 6 Oct 2014 01:17:20 +0900 Subject: [PATCH 178/205] add missed files --- widget/form/settings/generalsettings.ui | 81 ++++++++++++++++++++++ widget/form/settings/identitysettings.ui | 86 ++++++++++++++++++++++++ 2 files changed, 167 insertions(+) create mode 100644 widget/form/settings/generalsettings.ui create mode 100644 widget/form/settings/identitysettings.ui diff --git a/widget/form/settings/generalsettings.ui b/widget/form/settings/generalsettings.ui new file mode 100644 index 000000000..ca01dbc5b --- /dev/null +++ b/widget/form/settings/generalsettings.ui @@ -0,0 +1,81 @@ + + + GeneralSettings + + + + 0 + 0 + 527 + 367 + + + + Form + + + + 15 + + + 15 + + + 15 + + + + + Enable IPv6 (recommended) + + + + + + + Use translations + + + + + + + Save settings to the working directory instead of the usual conf dir + + + Make Tox portable + + + + + + + + + Smiley Pack + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + diff --git a/widget/form/settings/identitysettings.ui b/widget/form/settings/identitysettings.ui new file mode 100644 index 000000000..d27300155 --- /dev/null +++ b/widget/form/settings/identitysettings.ui @@ -0,0 +1,86 @@ + + + IdentitySettings + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + + Public Information + + + + + + Name + + + + + + + + + + Status + + + + + + + + + + + + + Tox ID + + + + + + Your Tox ID (click to copy) + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + CroppingLabel + QLabel +
widget/croppinglabel.h
+
+
+ + +
From 866f986d04e7605b79a0b282e302f47d082bc1f0 Mon Sep 17 00:00:00 2001 From: apprb Date: Mon, 6 Oct 2014 01:30:31 +0900 Subject: [PATCH 179/205] small fixes --- widget/form/settings/genericsettings.h | 9 +-------- widget/form/settings/identityform.cpp | 10 ++++------ widget/form/settings/identityform.h | 2 +- widget/form/settingswidget.cpp | 9 ++++++++- widget/form/settingswidget.h | 5 +++++ 5 files changed, 19 insertions(+), 16 deletions(-) diff --git a/widget/form/settings/genericsettings.h b/widget/form/settings/genericsettings.h index e3852ee28..e79ec7b06 100644 --- a/widget/form/settings/genericsettings.h +++ b/widget/form/settings/genericsettings.h @@ -27,14 +27,7 @@ public: GenericForm(const QString &name, const QPixmap &icon) : formName(name), formIcon(icon) {;} ~GenericForm() {;} - virtual void show(SettingsWidget& sw) - { -// sw.body->layout()->addWidget(&body); -// body.show(); -// sw.head->layout()->addWidget(&head); -// head.show(); - } - + virtual void updateContent() {;} QString getFormName() {return formName;} QPixmap getFormIcon() {return formIcon;} diff --git a/widget/form/settings/identityform.cpp b/widget/form/settings/identityform.cpp index bfc231c33..c2dac21b0 100644 --- a/widget/form/settings/identityform.cpp +++ b/widget/form/settings/identityform.cpp @@ -14,6 +14,7 @@ See the COPYING file for more details. */ +#include "core.h" #include "ui_identitysettings.h" #include "identityform.h" #include "widget/form/settingswidget.h" @@ -65,20 +66,17 @@ void IdentityForm::copyIdClicked() void IdentityForm::onUserNameEdited() { - emit userNameChanged(bodyUI->userName->text()); + Core::getInstance()->setUsername(bodyUI->userName->text()); } void IdentityForm::onStatusMessageEdited() { - emit statusMessageChanged(bodyUI->statusMessage->text()); + Core::getInstance()->setStatusMessage(bodyUI->statusMessage->text()); } -void IdentityForm::show(SettingsWidget& sw) +void IdentityForm::updateContent() { - bodyUI->userName->setText(Core::getInstance()->getUsername()); - bodyUI->statusMessage->setText(Core::getInstance()->getStatusMessage()); toxId->setText(Core::getInstance()->getSelfId().toString()); - GenericForm::show(sw); } void IdentityForm::setUserName(const QString &name) diff --git a/widget/form/settings/identityform.h b/widget/form/settings/identityform.h index 0cacb4dc7..c5505e6ea 100644 --- a/widget/form/settings/identityform.h +++ b/widget/form/settings/identityform.h @@ -50,7 +50,7 @@ public: void setUserName(const QString &name); void setStatusMessage(const QString &msg); - void show(SettingsWidget& sw); + virtual void updateContent(); signals: void userNameChanged(QString); diff --git a/widget/form/settingswidget.cpp b/widget/form/settingswidget.cpp index 047c5aaac..b4d208f61 100644 --- a/widget/form/settingswidget.cpp +++ b/widget/form/settingswidget.cpp @@ -33,7 +33,7 @@ SettingsWidget::SettingsWidget(Camera* cam, QWidget* parent) QVBoxLayout *bodyLayout = new QVBoxLayout(); body->setLayout(bodyLayout); - QTabWidget *settingsTabs = new QTabWidget(); + settingsTabs = new QTabWidget(); bodyLayout->addWidget(settingsTabs); GeneralForm *gfrm = new GeneralForm; @@ -46,6 +46,8 @@ SettingsWidget::SettingsWidget(Camera* cam, QWidget* parent) { settingsTabs->addTab(cfgForm, cfgForm->getFormIcon(), cfgForm->getFormName()); } + + connect(settingsTabs, SIGNAL(currentChanged(int)), this, SLOT(onTabChanged(int))); } SettingsWidget::~SettingsWidget() @@ -59,3 +61,8 @@ void SettingsWidget::show(Ui::MainWindow& ui) body->show(); head->show(); } + +void SettingsWidget::onTabChanged(int index) +{ + static_cast(this->settingsTabs->widget(index))->updateContent(); +} diff --git a/widget/form/settingswidget.h b/widget/form/settingswidget.h index 552af5104..713eddde8 100644 --- a/widget/form/settingswidget.h +++ b/widget/form/settingswidget.h @@ -25,6 +25,7 @@ class GeneralForm; class IdentityForm; class PrivacyForm; class AVForm; +class QTabWidget; namespace Ui {class MainWindow;} @@ -38,9 +39,13 @@ public: void show(Ui::MainWindow &ui); IdentityForm *getIdentityForm() {return ifrm;} +private slots: + void onTabChanged(int); + private: QWidget *head, *body; // keep the others private IdentityForm *ifrm; + QTabWidget *settingsTabs; }; #endif // SETTINGSWIDGET_H From 35aeca5dd05ea50aa17207821cd5b59f5766e87e Mon Sep 17 00:00:00 2001 From: apprb Date: Mon, 6 Oct 2014 03:02:12 +0900 Subject: [PATCH 180/205] cosmetic fixes --- widget/form/settings/generalsettings.ui | 74 +++++++++++++++---------- widget/form/settings/identityform.cpp | 10 ++-- widget/form/settings/identityform.h | 2 +- widget/form/settingswidget.cpp | 42 +++++++++++--- widget/form/settingswidget.h | 8 ++- 5 files changed, 89 insertions(+), 47 deletions(-) diff --git a/widget/form/settings/generalsettings.ui b/widget/form/settings/generalsettings.ui index ca01dbc5b..902d41039 100644 --- a/widget/form/settings/generalsettings.ui +++ b/widget/form/settings/generalsettings.ui @@ -24,43 +24,57 @@ 15 - - - Enable IPv6 (recommended) + + + General Settings + + + + + Enable IPv6 (recommended) + + + + + + + Use translations + + + + + + + Save settings to the working directory instead of the usual conf dir + + + Make Tox portable + + + + - - - Use translations + + + Theme + + + + + Smiley Pack + + + + + + + - - - - Save settings to the working directory instead of the usual conf dir - - - Make Tox portable - - - - - - - - - Smiley Pack - - - - - - - - diff --git a/widget/form/settings/identityform.cpp b/widget/form/settings/identityform.cpp index c2dac21b0..5aff0e513 100644 --- a/widget/form/settings/identityform.cpp +++ b/widget/form/settings/identityform.cpp @@ -37,11 +37,11 @@ IdentityForm::IdentityForm() : small.setPixelSize(13); small.setKerning(false); - toxId->setTextInteractionFlags(Qt::TextSelectableByMouse); +// toxId->setTextInteractionFlags(Qt::TextSelectableByMouse); toxId->setReadOnly(true); - toxId->setFrameStyle(QFrame::NoFrame); - toxId->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - toxId->setFixedHeight(toxId->document()->size().height()*2); +// toxId->setFrameStyle(QFrame::NoFrame); +// toxId->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); +// toxId->setFixedHeight(toxId->document()->size().height()*2); toxId->setFont(small); bodyUI->toxGroup->layout()->addWidget(toxId); @@ -59,7 +59,7 @@ IdentityForm::~IdentityForm() void IdentityForm::copyIdClicked() { toxId->selectAll(); - QString txt = toxId->toPlainText(); + QString txt = toxId->text(); txt.replace('\n',""); QApplication::clipboard()->setText(txt); } diff --git a/widget/form/settings/identityform.h b/widget/form/settings/identityform.h index c5505e6ea..2a4b07a77 100644 --- a/widget/form/settings/identityform.h +++ b/widget/form/settings/identityform.h @@ -29,7 +29,7 @@ namespace Ui { class IdentitySettings; } -class ClickableTE : public QTextEdit +class ClickableTE : public QLineEdit { Q_OBJECT public: diff --git a/widget/form/settingswidget.cpp b/widget/form/settingswidget.cpp index b4d208f61..434513004 100644 --- a/widget/form/settingswidget.cpp +++ b/widget/form/settingswidget.cpp @@ -22,19 +22,35 @@ #include "widget/form/settings/identityform.h" #include "widget/form/settings/privacyform.h" #include "widget/form/settings/avform.h" -#include +#include +#include SettingsWidget::SettingsWidget(Camera* cam, QWidget* parent) : QWidget(parent) { - body = new QWidget(); - head = new QWidget(); - + body = new QWidget(this); QVBoxLayout *bodyLayout = new QVBoxLayout(); body->setLayout(bodyLayout); - settingsTabs = new QTabWidget(); - bodyLayout->addWidget(settingsTabs); + head = new QWidget(this); + QHBoxLayout *headLayout = new QHBoxLayout(); + head->setLayout(headLayout); + + imgLabel = new QLabel(); + headLayout->addWidget(imgLabel); + + nameLabel = new QLabel(); + QFont bold; + bold.setBold(true); + nameLabel->setFont(bold); + headLayout->addWidget(nameLabel); + headLayout->addStretch(1); + + settingsWidgets = new QStackedWidget; + bodyLayout->addWidget(settingsWidgets); + + tabBar = new QTabBar; + bodyLayout->addWidget(tabBar); GeneralForm *gfrm = new GeneralForm; ifrm = new IdentityForm; @@ -44,10 +60,13 @@ SettingsWidget::SettingsWidget(Camera* cam, QWidget* parent) GenericForm *cfgForms[] = {gfrm, ifrm, pfrm, avfrm}; for (auto cfgForm : cfgForms) { - settingsTabs->addTab(cfgForm, cfgForm->getFormIcon(), cfgForm->getFormName()); + tabBar->addTab(cfgForm->getFormIcon(), ""); + settingsWidgets->addWidget(cfgForm); } + tabBar->setIconSize(QSize(20, 20)); + tabBar->setShape(QTabBar::RoundedSouth); - connect(settingsTabs, SIGNAL(currentChanged(int)), this, SLOT(onTabChanged(int))); + connect(tabBar, SIGNAL(currentChanged(int)), this, SLOT(onTabChanged(int))); } SettingsWidget::~SettingsWidget() @@ -60,9 +79,14 @@ void SettingsWidget::show(Ui::MainWindow& ui) ui.mainHead->layout()->addWidget(head); body->show(); head->show(); + onTabChanged(tabBar->currentIndex()); } void SettingsWidget::onTabChanged(int index) { - static_cast(this->settingsTabs->widget(index))->updateContent(); + this->settingsWidgets->setCurrentIndex(index); + GenericForm *currentWidget = static_cast(this->settingsWidgets->widget(index)); + currentWidget->updateContent(); + nameLabel->setText(currentWidget->getFormName()); + imgLabel->setPixmap(currentWidget->getFormIcon().scaledToHeight(40, Qt::SmoothTransformation)); } diff --git a/widget/form/settingswidget.h b/widget/form/settingswidget.h index 713eddde8..431e52c1c 100644 --- a/widget/form/settingswidget.h +++ b/widget/form/settingswidget.h @@ -25,7 +25,9 @@ class GeneralForm; class IdentityForm; class PrivacyForm; class AVForm; -class QTabWidget; +class QTabBar; +class QStackedWidget; +class QLabel; namespace Ui {class MainWindow;} @@ -45,7 +47,9 @@ private slots: private: QWidget *head, *body; // keep the others private IdentityForm *ifrm; - QTabWidget *settingsTabs; + QStackedWidget *settingsWidgets; + QTabBar *tabBar; + QLabel *nameLabel, *imgLabel; }; #endif // SETTINGSWIDGET_H From d1c042ed5e608b0ddb381912be68ecfa9df655eb Mon Sep 17 00:00:00 2001 From: dubslow Date: Sun, 5 Oct 2014 22:47:12 -0500 Subject: [PATCH 181/205] add Kappa emote --- smileys/default/Kappa.png | Bin 0 -> 1242 bytes smileys/default/emoticons.xml | 3 +++ 2 files changed, 3 insertions(+) create mode 100644 smileys/default/Kappa.png diff --git a/smileys/default/Kappa.png b/smileys/default/Kappa.png new file mode 100644 index 0000000000000000000000000000000000000000..a7ebbec4d90af0efba51de1a263d08793ce3a67a GIT binary patch literal 1242 zcmeAS@N?(olHy`uVBq!ia0vp^l0YoO!2%@hbniq1DW)WEcNYeRRlUkaKptm-M`SUO z_5fqIli7Aa6^A`t978NlmtOJCo|7uk@bLBQmn!jUlYP?E)K+$?nO&e-OZw?oizWA8?#p0*xnjemD)|Aek7ijS0@{5&Eu5VbPmhBpTYemmI z)75Y@A8(s2wX8>D=OcC9%JWv{ z3gL%cHLuS-Hcxl^lu}XMij$g)laiB+<0K|*Uu1un)v>AR`<$)M_N^24)7qKgace{7 z(PsYBGfPiSv5ibVHYZ^EMPbj`+m~uw3$pf5^VMFl`t@mvNt41a1|C_mrzg?cjBiq> zhU~9jm#n0AHFd4pGp&$6WJ~XjYc?JkS;~v^<6T3~f1b52<94X|+RXPC_x@8a4B@MM z+@vV{YtyG7G2NR2U#7Y&I@}VzID4V0_9WxH!={e+_eBKX+R^5}=r~8Ibx~5N^Ng^~ zYm^MvX1u*vZ!5U;y_3>n?TVvwLQ_{)b(Q7(QmXPg{=;a(c8%q$(xQV??ml;S%`}K_ zU$cjkwKlpeq^3rp&Rs~ay|&iU@$9_wd{;lk>zWCB&W*|x0H$lz64!{5l*E!$tK_0o zAjM#0U}&UkV61Ck7Gh{>WngS&Y^rNuVP#;zu(-L1;F+74p6Z*Jo|&AjV5SFzx<(2>D-CqPwkiY~nki(IloVL$>z9|8>t%ve z12IswUVc%!gP83hpotP76GJjebCayBT=J7kb5rw5tgHfnN{bl`m;c|b4^$(Lqy}uK zl~qP+W_m^mgONq>=|vnsC1RLL!ZTA!G8l|Z!&TXD + + :Kappa: + From 227e483bdd43fb2759ac07b7b35f15a5b5661e02 Mon Sep 17 00:00:00 2001 From: dubslow Date: Mon, 6 Oct 2014 00:49:26 -0500 Subject: [PATCH 182/205] tweak buildPackages --- tools/buildPackages.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/buildPackages.sh b/tools/buildPackages.sh index 0c12e11c6..501d7b429 100755 --- a/tools/buildPackages.sh +++ b/tools/buildPackages.sh @@ -87,7 +87,7 @@ mv qTox-master $VERNAME # Build packages cd $VERNAME -./bootstrap.sh +./bootstrap.sh --local debuild -us -uc -aamd64 debuild -us -uc -ai386 cd .. From 9e2195c03cb8291115e4bc4deef46fcda1b4627c Mon Sep 17 00:00:00 2001 From: dubslow Date: Mon, 6 Oct 2014 01:46:30 -0500 Subject: [PATCH 183/205] simplify groupchat names, fix #379, more simplification is possible --- core.cpp | 5 +-- core.h | 2 +- group.cpp | 57 +++------------------------------ group.h | 6 ---- widget/form/genericchatform.cpp | 6 ++++ widget/form/groupchatform.cpp | 11 ------- widget/form/groupchatform.h | 1 - widget/widget.cpp | 10 +++--- widget/widget.h | 2 +- 9 files changed, 20 insertions(+), 80 deletions(-) diff --git a/core.cpp b/core.cpp index f6b7a2a5c..fddca6eda 100644 --- a/core.cpp +++ b/core.cpp @@ -402,9 +402,10 @@ void Core::onGroupInvite(Tox*, int friendnumber, const uint8_t *group_public_key emit static_cast(core)->groupInviteReceived(friendnumber, group_public_key,length); } -void Core::onGroupMessage(Tox*, int groupnumber, int friendgroupnumber, const uint8_t * message, uint16_t length, void *core) +void Core::onGroupMessage(Tox*, int groupnumber, int peernumber, const uint8_t * message, uint16_t length, void *_core) { - emit static_cast(core)->groupMessageReceived(groupnumber, friendgroupnumber, CString::toString(message, length)); + Core* core = static_cast(_core); + emit core->groupMessageReceived(groupnumber, CString::toString(message, length), core->getGroupPeerName(groupnumber, peernumber)); } void Core::onGroupNamelistChange(Tox*, int groupnumber, int peernumber, uint8_t change, void *core) diff --git a/core.h b/core.h index b1b8c3f43..51d885688 100644 --- a/core.h +++ b/core.h @@ -118,7 +118,7 @@ signals: void emptyGroupCreated(int groupnumber); void groupInviteReceived(int friendnumber, const uint8_t *group_public_key,uint16_t length); - void groupMessageReceived(int groupnumber, int friendgroupnumber, const QString& message); + void groupMessageReceived(int groupnumber, const QString& message, const QString& author); void groupNamelistChanged(int groupnumber, int peernumber, uint8_t change); void usernameSet(const QString& username); diff --git a/group.cpp b/group.cpp index 4898f525a..d74610131 100644 --- a/group.cpp +++ b/group.cpp @@ -24,16 +24,14 @@ #include Group::Group(int GroupId, QString Name) - : groupId(GroupId), nPeers{0}, hasPeerInfo{false}, peerInfoTimer{new QTimer} + : groupId(GroupId), nPeers{0} { widget = new GroupWidget(groupId, Name); chatForm = new GroupChatForm(this); - connect(peerInfoTimer, SIGNAL(timeout()), this, SLOT(queryPeerInfo())); - peerInfoTimer->setInterval(500); - peerInfoTimer->setSingleShot(false); - //peerInfoTimer.start(); - //in groupchats, we only notify on messages containing your name + //in groupchats, we only notify on messages containing your name <-- dumb + // sound notifications should be on all messages, but system popup notification + // on naming is appropriate hasNewMessages = 0; userWasMentioned = 0; } @@ -42,53 +40,6 @@ Group::~Group() { delete chatForm; delete widget; - delete peerInfoTimer; -} - -void Group::queryPeerInfo() -{ - const Core* core = Core::getInstance(); - int nPeersResult = core->getGroupNumberPeers(groupId); - if (nPeersResult == -1) - { - qDebug() << "Group::queryPeerInfo: Can't get number of peers"; - return; - } - nPeers = nPeersResult; - widget->onUserListChanged(); - chatForm->onUserListChanged(); - - if (nPeersResult == 0) - return; - - bool namesOk = true; - QList names = core->getGroupPeerNames(groupId); - if (names.isEmpty()) - { - qDebug() << "Group::queryPeerInfo: Can't get names of peers"; - return; - } - for (int i=0; ionUserListChanged(); - chatForm->onUserListChanged(); - - if (namesOk) - { - qDebug() << "Group::queryPeerInfo: Successfully loaded names"; - hasPeerInfo = true; - peerInfoTimer->stop(); - } } void Group::addPeer(int peerId, QString name) diff --git a/group.h b/group.h index fed4b11ee..cd263538f 100644 --- a/group.h +++ b/group.h @@ -25,7 +25,6 @@ struct Friend; class GroupWidget; class GroupChatForm; -class QTimer; class Group : public QObject { @@ -37,17 +36,12 @@ public: void removePeer(int peerId); void updatePeer(int peerId, QString newName); -private slots: - void queryPeerInfo(); - public: int groupId; QMap peers; int nPeers; GroupWidget* widget; GroupChatForm* chatForm; - bool hasPeerInfo; - QTimer* peerInfoTimer; int hasNewMessages, userWasMentioned; }; diff --git a/widget/form/genericchatform.cpp b/widget/form/genericchatform.cpp index 4a73d3938..08e8040bb 100644 --- a/widget/form/genericchatform.cpp +++ b/widget/form/genericchatform.cpp @@ -172,6 +172,12 @@ void GenericChatForm::addMessage(QString author, QString message, bool isAction, QString date = datetime.toString(Settings::getInstance().getTimestampFormat()); bool isMe = (author == Widget::getInstance()->getUsername()); + if (!isAction && message.startsWith("/me ")) + { // always render actions regardless of what core thinks + isAction = true; + message = message.right(message.length()-4); + } + if (isAction) { chatWidget->insertMessage(new ActionAction (getElidedName(author), message, date, isMe)); diff --git a/widget/form/groupchatform.cpp b/widget/form/groupchatform.cpp index 412ef46e8..5e97d22df 100644 --- a/widget/form/groupchatform.cpp +++ b/widget/form/groupchatform.cpp @@ -80,17 +80,6 @@ void GroupChatForm::onSendTriggered() emit sendMessage(group->groupId, msg); } -void GroupChatForm::addGroupMessage(QString message, int peerId) -{ - QString msgAuthor; - if (group->peers.contains(peerId)) - msgAuthor = group->peers[peerId]; - else - msgAuthor = tr(""); - - addMessage(msgAuthor, message); -} - void GroupChatForm::onUserListChanged() { nusersLabel->setText(tr("%1 users in chat").arg(group->nPeers)); diff --git a/widget/form/groupchatform.h b/widget/form/groupchatform.h index a544034de..6b3984b06 100644 --- a/widget/form/groupchatform.h +++ b/widget/form/groupchatform.h @@ -28,7 +28,6 @@ class GroupChatForm : public GenericChatForm public: GroupChatForm(Group* chatGroup); - void addGroupMessage(QString message, int peerId); void onUserListChanged(); private slots: diff --git a/widget/widget.cpp b/widget/widget.cpp index bfe0a483a..5cbaa74ee 100644 --- a/widget/widget.cpp +++ b/widget/widget.cpp @@ -209,7 +209,7 @@ void Widget::closeEvent(QCloseEvent *event) QString Widget::getUsername() { - return ui->nameLabel->text(); + return core->getUsername(); } Camera* Widget::getCamera() @@ -558,21 +558,21 @@ void Widget::onGroupInviteReceived(int32_t friendId, const uint8_t* publicKey,ui } } -void Widget::onGroupMessageReceived(int groupnumber, int friendgroupnumber, const QString& message) +void Widget::onGroupMessageReceived(int groupnumber, const QString& message, const QString& author) { Group* g = GroupList::findGroup(groupnumber); if (!g) return; - g->chatForm->addGroupMessage(message, friendgroupnumber); + g->chatForm->addMessage(author, message); if ((static_cast(g->widget) != activeChatroomWidget) || isMinimized() || !isActiveWindow()) { g->hasNewMessages = 1; + newMessageAlert(); // sound alert on any message, not just naming user if (message.contains(core->getUsername(), Qt::CaseInsensitive)) { - newMessageAlert(); - g->userWasMentioned = 1; + g->userWasMentioned = 1; // useful for highlighting line or desktop notifications } g->widget->updateStatusLight(); } diff --git a/widget/widget.h b/widget/widget.h index 3d7858e78..7e17f565f 100644 --- a/widget/widget.h +++ b/widget/widget.h @@ -92,7 +92,7 @@ private slots: void onFriendRequestReceived(const QString& userId, const QString& message); void onEmptyGroupCreated(int groupId); void onGroupInviteReceived(int32_t friendId, const uint8_t *publicKey,uint16_t length); - void onGroupMessageReceived(int groupnumber, int friendgroupnumber, const QString& message); + void onGroupMessageReceived(int groupnumber, const QString& message, const QString& author); void onGroupNamelistChanged(int groupnumber, int peernumber, uint8_t change); void removeFriend(int friendId); void copyFriendIdToClipboard(int friendId); From 200c6d30e9d77be52de914b12d85adbef5358ef4 Mon Sep 17 00:00:00 2001 From: dubslow Date: Mon, 6 Oct 2014 03:21:47 -0500 Subject: [PATCH 184/205] reduce font size and space between chat lines --- ui/chatArea/innerStyle.css | 14 +++++++------- widget/chatareawidget.cpp | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ui/chatArea/innerStyle.css b/ui/chatArea/innerStyle.css index 823c8dfbe..444d4381b 100644 --- a/ui/chatArea/innerStyle.css +++ b/ui/chatArea/innerStyle.css @@ -1,36 +1,36 @@ div.name { color: @black; - font: @bigBold; + font: @mediumBold; } div.message { color: @black; - font: @big; + font: @medium; } div.action { color: #1818FF; - font: @big; + font: @medium; } div.date { color: @black; - font: @big; + font: @medium; } div.name_me { color: @mediumGrey; - font: @big; + font: @medium; } div.message_me { color: @black; - font: @big; + font: @medium; } div.date_me { color: @black; - font: @big; + font: @medium; } span.quote { diff --git a/widget/chatareawidget.cpp b/widget/chatareawidget.cpp index c743574fa..d3d326b63 100644 --- a/widget/chatareawidget.cpp +++ b/widget/chatareawidget.cpp @@ -38,7 +38,7 @@ ChatAreaWidget::ChatAreaWidget(QWidget *parent) setFrameStyle(QFrame::NoFrame); QTextTableFormat tableFormat; - tableFormat.setCellSpacing(15); + tableFormat.setCellSpacing(5); tableFormat.setBorderStyle(QTextFrameFormat::BorderStyle_None); tableFormat.setColumnWidthConstraints({QTextLength(QTextLength::FixedLength,nameWidth), QTextLength(QTextLength::PercentageLength,100), From 6e02240b561f9350c7300626199bf9bd7c012bec Mon Sep 17 00:00:00 2001 From: apprb Date: Mon, 6 Oct 2014 23:39:07 +0900 Subject: [PATCH 185/205] relative to system wide default font sizes in css --- misc/style.cpp | 18 +++++++++++------- misc/style.h | 14 +++++++------- ui/window/statusPanel.css | 2 +- 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/misc/style.cpp b/misc/style.cpp index 1c83f0c6e..6d7b191a2 100644 --- a/misc/style.cpp +++ b/misc/style.cpp @@ -23,6 +23,7 @@ #include #include #include +#include // helper functions QFont appFont(int pixelSize, int weight) @@ -78,14 +79,17 @@ QFont Style::getFont(Style::Font font) { // fonts as defined in // https://github.com/ItsDuke/Tox-UI/blob/master/UI%20GUIDELINES.md + + static int defSize = QFontInfo(QFont()).pixelSize(); + static QFont fonts[] = { - appFont(16, QFont::Bold), - appFont(14, QFont::Normal), - appFont(14, QFont::Bold), - appFont(13, QFont::Normal), - appFont(13, QFont::Bold), - appFont(12, QFont::Normal), - appFont(12, QFont::Light), + appFont(defSize + 2, QFont::Bold), + appFont(defSize , QFont::Normal), + appFont(defSize , QFont::Bold), + appFont(defSize - 1, QFont::Normal), + appFont(defSize - 1, QFont::Bold), + appFont(defSize - 2, QFont::Normal), + appFont(defSize - 2, QFont::Light), }; return fonts[font]; diff --git a/misc/style.h b/misc/style.h index 35c0b7e98..a07064e04 100644 --- a/misc/style.h +++ b/misc/style.h @@ -41,13 +41,13 @@ public: enum Font { - ExtraBig, // 14px, bold - Big, // 12px - BigBold, // 12px, bold - Medium, // 11px - MediumBold, // 11px, bold - Small, // 10px - SmallLight // 10px, light + ExtraBig, // [SystemDefault + 2]px, bold + Big, // [SystemDefault ]px + BigBold, // [SystemDefault ]px, bold + Medium, // [SystemDefault - 1]px + MediumBold, // [SystemDefault - 1]px, bold + Small, // [SystemDefault - 2]px + SmallLight // [SystemDefault - 2]px, light }; static QString getStylesheet(const QString& filename); diff --git a/ui/window/statusPanel.css b/ui/window/statusPanel.css index 3a0fc36da..4683bc15a 100644 --- a/ui/window/statusPanel.css +++ b/ui/window/statusPanel.css @@ -9,7 +9,7 @@ } #statusPanel > #statusHead > #statusLabel { - font: @smallLight; + font: @medium; color: @lightGrey; } From d42f9d31662a4d805d92ef80ea7f49a43d99fbee Mon Sep 17 00:00:00 2001 From: dubslow Date: Mon, 6 Oct 2014 09:57:50 -0500 Subject: [PATCH 186/205] Revert "reduce font size and space between chat lines", use #386 This reverts commit 200c6d30e9d77be52de914b12d85adbef5358ef4. --- ui/chatArea/innerStyle.css | 14 +++++++------- widget/chatareawidget.cpp | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ui/chatArea/innerStyle.css b/ui/chatArea/innerStyle.css index 444d4381b..823c8dfbe 100644 --- a/ui/chatArea/innerStyle.css +++ b/ui/chatArea/innerStyle.css @@ -1,36 +1,36 @@ div.name { color: @black; - font: @mediumBold; + font: @bigBold; } div.message { color: @black; - font: @medium; + font: @big; } div.action { color: #1818FF; - font: @medium; + font: @big; } div.date { color: @black; - font: @medium; + font: @big; } div.name_me { color: @mediumGrey; - font: @medium; + font: @big; } div.message_me { color: @black; - font: @medium; + font: @big; } div.date_me { color: @black; - font: @medium; + font: @big; } span.quote { diff --git a/widget/chatareawidget.cpp b/widget/chatareawidget.cpp index d3d326b63..c743574fa 100644 --- a/widget/chatareawidget.cpp +++ b/widget/chatareawidget.cpp @@ -38,7 +38,7 @@ ChatAreaWidget::ChatAreaWidget(QWidget *parent) setFrameStyle(QFrame::NoFrame); QTextTableFormat tableFormat; - tableFormat.setCellSpacing(5); + tableFormat.setCellSpacing(15); tableFormat.setBorderStyle(QTextFrameFormat::BorderStyle_None); tableFormat.setColumnWidthConstraints({QTextLength(QTextLength::FixedLength,nameWidth), QTextLength(QTextLength::PercentageLength,100), From b9a666159aa84cd000891d7778d6bad7ae7a22bc Mon Sep 17 00:00:00 2001 From: dubslow Date: Mon, 6 Oct 2014 09:58:48 -0500 Subject: [PATCH 187/205] reduce space between chat lines --- widget/chatareawidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/widget/chatareawidget.cpp b/widget/chatareawidget.cpp index c743574fa..d3d326b63 100644 --- a/widget/chatareawidget.cpp +++ b/widget/chatareawidget.cpp @@ -38,7 +38,7 @@ ChatAreaWidget::ChatAreaWidget(QWidget *parent) setFrameStyle(QFrame::NoFrame); QTextTableFormat tableFormat; - tableFormat.setCellSpacing(15); + tableFormat.setCellSpacing(5); tableFormat.setBorderStyle(QTextFrameFormat::BorderStyle_None); tableFormat.setColumnWidthConstraints({QTextLength(QTextLength::FixedLength,nameWidth), QTextLength(QTextLength::PercentageLength,100), From d093679d03bfeeae62aaceaa388a85391640673b Mon Sep 17 00:00:00 2001 From: dubslow Date: Sun, 5 Oct 2014 15:49:44 -0500 Subject: [PATCH 188/205] Add proxy support --- core.cpp | 57 ++++++++++++++++++++----- core.h | 1 + misc/cstring.h | 3 +- misc/settings.cpp | 36 ++++++++++++++++ misc/settings.h | 13 ++++++ widget/form/settings/generalform.cpp | 42 ++++++++++++++++-- widget/form/settings/generalform.h | 3 ++ widget/form/settings/generalsettings.ui | 46 ++++++++++++++++++++ widget/form/settingswidget.cpp | 2 +- widget/widget.cpp | 13 +++++- widget/widget.h | 1 + 11 files changed, 199 insertions(+), 18 deletions(-) diff --git a/core.cpp b/core.cpp index f6b7a2a5c..fdc91616a 100644 --- a/core.cpp +++ b/core.cpp @@ -121,6 +121,9 @@ void Core::start() { // IPv6 needed for LAN discovery, but can crash some weird routers. On by default, can be disabled in options. bool enableIPv6 = Settings::getInstance().getEnableIPv6(); + bool forceTCP = Settings::getInstance().getForceTCP(); + QString proxyAddr = Settings::getInstance().getProxyAddr(); + int proxyPort = Settings::getInstance().getProxyPort(); if (enableIPv6) qDebug() << "Core starting with IPv6 enabled"; else @@ -128,10 +131,28 @@ void Core::start() Tox_Options toxOptions; toxOptions.ipv6enabled = enableIPv6; - toxOptions.udp_disabled = 0; - toxOptions.proxy_enabled = false; - toxOptions.proxy_address[0] = 0; - toxOptions.proxy_port = 0; + toxOptions.udp_disabled = forceTCP; + if (proxyAddr.length() > 255) + { + qWarning() << "Core: proxy address" << proxyAddr << "is too long"; + toxOptions.proxy_enabled = false; + toxOptions.proxy_address[0] = 0; + toxOptions.proxy_port = 0; + } + else if (proxyAddr != "" && proxyPort > 0) + { + qDebug() << "Core: using proxy" << proxyAddr << ":" << proxyPort; + toxOptions.proxy_enabled = true; + uint16_t sz = CString::fromString(proxyAddr, (unsigned char*)toxOptions.proxy_address); + toxOptions.proxy_address[sz] = 0; + toxOptions.proxy_port = proxyPort; + } + else + { + toxOptions.proxy_enabled = false; + toxOptions.proxy_address[0] = 0; + toxOptions.proxy_port = 0; + } tox = tox_new(&toxOptions); if (tox == nullptr) @@ -142,13 +163,29 @@ void Core::start() tox = tox_new(&toxOptions); if (tox == nullptr) { - qCritical() << "Tox core failed to start"; - emit failedToStart(); + if (toxOptions.proxy_enabled) + { + //QMessageBox::critical(Widget::getInstance(), tr("Proxy failure", "popup title"), + //tr("toxcore failed to start with your proxy settings. qTox cannot run; please modify your " + //"settings and restart.", "popup text")); + qCritical() << "Core: bad proxy! no toxcore!"; + emit badProxy(); + } + else + { + qCritical() << "Tox core failed to start"; + emit failedToStart(); + } return; - } + } else qWarning() << "Core failed to start with IPv6, falling back to IPv4. LAN discovery may not work properly."; } + else if (toxOptions.proxy_enabled) + { + emit badProxy(); + return; + } else { qCritical() << "Tox core failed to start"; @@ -919,8 +956,6 @@ void Core::setAvatar(uint8_t format, const QByteArray& data) qWarning() << "Core: Failed to set self avatar"; return; } - else - qDebug() << "Core: Set avatar, format:"< GeneralForm::GeneralForm() : GenericForm(tr("General Settings"), QPixmap(":/img/settings/general.png")) @@ -37,10 +38,20 @@ GeneralForm::GeneralForm() : } bodyUI->smileyPackBrowser->setCurrentIndex(bodyUI->smileyPackBrowser->findData(Settings::getInstance().getSmileyPack())); - connect(bodyUI->cbEnableIPv6, SIGNAL(stateChanged(int)), this, SLOT(onEnableIPv6Updated())); - connect(bodyUI->cbUseTranslations, SIGNAL(stateChanged(int)), this, SLOT(onUseTranslationUpdated())); - connect(bodyUI->cbMakeToxPortable, SIGNAL(stateChanged(int)), this, SLOT(onMakeToxPortableUpdated())); + bodyUI->cbUDPDisabled->setChecked(Settings::getInstance().getForceTCP()); + bodyUI->proxyAddr->setText(Settings::getInstance().getProxyAddr()); + int port = Settings::getInstance().getProxyPort(); + if (port != -1) + bodyUI->proxyPort->setText(QString::number(port)); + + connect(bodyUI->cbEnableIPv6, &QCheckBox::stateChanged, this, &GeneralForm::onEnableIPv6Updated); + connect(bodyUI->cbUseTranslations, &QCheckBox::stateChanged, this, &GeneralForm::onUseTranslationUpdated); + connect(bodyUI->cbMakeToxPortable, &QCheckBox::stateChanged, this, &GeneralForm::onMakeToxPortableUpdated); connect(bodyUI->smileyPackBrowser, SIGNAL(currentIndexChanged(int)), this, SLOT(onSmileyBrowserIndexChanged(int))); + // new syntax can't handle overloaded signals... (at least not in a pretty way) + connect(bodyUI->cbUDPDisabled, &QCheckBox::stateChanged, this, &GeneralForm::onUDPUpdated); + connect(bodyUI->proxyAddr, &QLineEdit::editingFinished, this, &GeneralForm::onProxyAddrEdited); + connect(bodyUI->proxyPort, &QLineEdit::editingFinished, this, &GeneralForm::onProxyPortEdited); } GeneralForm::~GeneralForm() @@ -68,3 +79,28 @@ void GeneralForm::onSmileyBrowserIndexChanged(int index) QString filename = bodyUI->smileyPackBrowser->itemData(index).toString(); Settings::getInstance().setSmileyPack(filename); } + +void GeneralForm::onUDPUpdated() +{ + Settings::getInstance().setForceTCP(bodyUI->cbUDPDisabled->isChecked()); +} + +void GeneralForm::onProxyAddrEdited() +{ + Settings::getInstance().setProxyAddr(bodyUI->proxyAddr->text()); +} + +void GeneralForm::onProxyPortEdited() +{ + QString text = bodyUI->proxyPort->text(); + if (text != "") + { + int port = text.toInt(); + if (port < 1) + QMessageBox::warning(bodyUI->proxyPort, tr("Bad port", "title of bad port popup"), tr("The port you entered is invalid; please enter another.", "text of bad port popup")); + else + Settings::getInstance().setProxyPort(port); + } + else + Settings::getInstance().setProxyPort(-1); +} diff --git a/widget/form/settings/generalform.h b/widget/form/settings/generalform.h index 5d5fd6efe..2af8f4bb6 100644 --- a/widget/form/settings/generalform.h +++ b/widget/form/settings/generalform.h @@ -37,6 +37,9 @@ private slots: void onUseTranslationUpdated(); void onMakeToxPortableUpdated(); void onSmileyBrowserIndexChanged(int index); + void onUDPUpdated(); + void onProxyAddrEdited(); + void onProxyPortEdited(); private: Ui::GeneralSettings *bodyUI; diff --git a/widget/form/settings/generalsettings.ui b/widget/form/settings/generalsettings.ui index 902d41039..0015d1787 100644 --- a/widget/form/settings/generalsettings.ui +++ b/widget/form/settings/generalsettings.ui @@ -75,6 +75,52 @@
+ + + + Proxy settings + + + + + + Disable UDP (not recommended) + + + + + + + + + Proxy address + + + + + + + Proxy port + + + + + + + + + + + + + + + + + + + + diff --git a/widget/form/settingswidget.cpp b/widget/form/settingswidget.cpp index 434513004..b7539a4c5 100644 --- a/widget/form/settingswidget.cpp +++ b/widget/form/settingswidget.cpp @@ -66,7 +66,7 @@ SettingsWidget::SettingsWidget(Camera* cam, QWidget* parent) tabBar->setIconSize(QSize(20, 20)); tabBar->setShape(QTabBar::RoundedSouth); - connect(tabBar, SIGNAL(currentChanged(int)), this, SLOT(onTabChanged(int))); + connect(tabBar, &QTabBar::currentChanged, this, &SettingsWidget::onTabChanged); } SettingsWidget::~SettingsWidget() diff --git a/widget/widget.cpp b/widget/widget.cpp index 283900fdc..ad08389bf 100644 --- a/widget/widget.cpp +++ b/widget/widget.cpp @@ -124,6 +124,7 @@ Widget::Widget(QWidget *parent) connect(core, &Core::connected, this, &Widget::onConnected); connect(core, &Core::disconnected, this, &Widget::onDisconnected); connect(core, &Core::failedToStart, this, &Widget::onFailedToStartCore); + connect(core, &Core::badProxy, this, &Widget::onBadProxyCore); connect(core, &Core::statusSet, this, &Widget::onStatusSet); connect(core, &Core::usernameSet, this, &Widget::setUsername); connect(core, &Core::statusMessageSet, this, &Widget::setStatusMessage); @@ -283,12 +284,22 @@ void Widget::onDisconnected() void Widget::onFailedToStartCore() { QMessageBox critical(this); - critical.setText("Toxcore failed to start, the application will terminate after you close this message."); + critical.setText(tr("Toxcore failed to start, the application will terminate after you close this message.")); critical.setIcon(QMessageBox::Critical); critical.exec(); qApp->quit(); } +void Widget::onBadProxyCore() +{ + QMessageBox critical(this); + critical.setText(tr("toxcore failed to start with your proxy settings. qTox cannot run; please modify your " + "settings and restart.", "popup text")); + critical.setIcon(QMessageBox::Critical); + critical.exec(); + onSettingsClicked(); +} + void Widget::onStatusSet(Status status) { //We have to use stylesheets here, there's no way to diff --git a/widget/widget.h b/widget/widget.h index fa371a9b2..aae819adc 100644 --- a/widget/widget.h +++ b/widget/widget.h @@ -77,6 +77,7 @@ private slots: void onTransferClicked(); void onSettingsClicked(); void onFailedToStartCore(); + void onBadProxyCore(); void onAvatarClicked(); void onSelfAvatarLoaded(const QPixmap &pic); void onUsernameChanged(const QString& newUsername, const QString& oldUsername); From dc73d5658a9605c934dbdd87facc554bd9ea0913 Mon Sep 17 00:00:00 2001 From: dubslow Date: Sun, 5 Oct 2014 16:03:22 -0500 Subject: [PATCH 189/205] add tooltip --- widget/form/settings/generalsettings.ui | 3 +++ 1 file changed, 3 insertions(+) diff --git a/widget/form/settings/generalsettings.ui b/widget/form/settings/generalsettings.ui index 0015d1787..7057866a8 100644 --- a/widget/form/settings/generalsettings.ui +++ b/widget/form/settings/generalsettings.ui @@ -86,6 +86,9 @@ Disable UDP (not recommended) + + This allows, e.g., toxing over Tor. It adds load to the Tox network however, so use only when necessary. + From b898e55b75d6d45c10bcaf21f1836ef43c3aa6b1 Mon Sep 17 00:00:00 2001 From: Ilya87 Date: Tue, 7 Oct 2014 00:52:22 +0400 Subject: [PATCH 190/205] Update Russian translation --- translations/ru.qm | Bin 6581 -> 9681 bytes translations/ru.ts | 501 ++++++++++++++++++++++----------------------- 2 files changed, 242 insertions(+), 259 deletions(-) diff --git a/translations/ru.qm b/translations/ru.qm index 50ef1c79f7626d2a63376a1e2b030909131555d6..f3d7a3e2aaf52ae9705de7a7fee08a57647cba6a 100644 GIT binary patch literal 9681 zcmcgxX>1&48UEai?=z0uq=^$IY15{`b)DEw9LIKI@8)pgI!+v?DiVRo?%1AWcV;^~ zwqx-J1W1KakbrVE2oN{?pinLq5J;3m6(FIu9O4oJfhr*?#3@98=Xt-G**jEJ(8`(J z*_royzvsQ4_x;AcnBMZ#^Vc5v?#|w?zVZWK`Pr0GH+@VQ55GaF?Y~jRwT~;cW234+ zIjq!{>#Fg}vQoW2Q8(||p;YISYUrPaQf)Kp(9Z_(eN|sKUR2|2Z&RwfQBAJkTK@%g z>cAsPZ5vTD@4f_iA675>9pv@wQ;%MM2KO(k_r0QCsf~}RZ=A|w-3Il&H$IE!M%DA* z`8}SybW`W$6rTI*hFkvfxKeeOH%xE)JJ$X3hNs^7dgz)+J+A*I?k*MH)nuPb%yYwJJ% zp=Yqq1NwUF6ZOwt*ns`Nz2VB%uK~AIgV%=l8Xsx!k_$>T|ERHU3-#FD*s}Ybke_Q@ z@_T?^U*p$@{*32--1yXQUkjYy+f?_O*D1B(@upWl(};Ed+4Pa82NnKnZhzo=ShuhF z=J)&(&o?wbcXN3j_2ey@LV*8DkK+j2I4F6K+;TI}; ze%V|5zlv^|yf7bPBY^CvigXM~3_?dGu9c#Cu>F0&m9J}ThX6*xI0!%v#iCj#(`oa# z@7Qiy?9-0#`fF^a0b_@85<>RD@&hmtO-2vkwFGBns-&7#^Re))$9&)O&9!AGW1AVz zy889g#(V92-deJ2yn0H^egHc@j9nfQhaFIT z;#2z}jLte`4CDJK7C4Ikhw*6&i<~wNLG|;>Q&(}FR>^qD?Q6mlgXHlYg*>2 zm2uMMdGD$@ovfkAEby8Vbc(@02*pCgpu)HyIV3yfQ-`D7QeFH-rkXL%#L8@%hmp)h zv6boD53Jbv;D#!2*He*EWKr&Z5{oiej~WMv2<}wkajXU&{pXi$T2G7#L#91DZ@OM! zraU*WUMN7LMmJVvaEgYsiFO>(k*-Az$MNqV(o1#A?ER0Lxa&7I(=G&?-~&Ad1Or(O zp9%gja2klA-*$f4$(vR>?ZX8NySA@7HBHb~)u9@0=s7!#LeMf9jzNuavzO#lpy;YM;5{n%&4#x|$O3HvN zBwz|^N-SGJoY?mooAEqTdlFtkdk=gj(3p<9EEJ({ZFpA-pcaEWQ~a#=Gaq0a zYWsOP+clk_CF#+O=9=XOeBSn1J_2TsNS4HF0kE++8b-JYC`&)5=L|t^VD8?X6JU|rHC?>P?JpZ6^{zi9i@Za%Qwlr~kb)Y@Z!k!FwJ zsdOQ0)uua!E>v6I$Bf&cADw6tSHwvSGAdlfK6r3FYO6t%iLzp_OnhtPaI)9 z!bsy;0qUKGx8F=Gdmc<`q3SK$exC_`0}n{q89Zp4c}ht;R>oWEXTa4)t4o4!5W16+ zfm6p?H7C6_H{)44fi}~A`8Z}x#FvJJUag~***r9xaXJ>$6&W3&Dl(`~nY1nex|$M= z3%Oblep^I<)X&3RH8wUSk*F zl7bd`OSm@j@MsLx=2D3$twJb) zX2wIvovaU&aL&78M7AfLJgc9%keoC3usb0i&1TU(+3C9oPiKf(1X-Axx*@uB`DrY^ zst$+(FJ$RkkGZn)^xWzJbI%J}_C?vb>PB`61%s!-XGnwg#}?-n*z}FXSZ%zQS%Nf% zW{fyPRk2%)E`$h0u)OOu%EVeITVgCCv<`3Q##+CfMzSslqz_KTlNGlg$Dep$3x zx@jM_xa?St;QJAB0DLZ95xyQwFe;WZj&zQdepUYm%Z15%FvF zNEBJ=K&oM1cZU%bL6)9_z>Njy3}ahb2x3BqgXiMjQMt!{Z$UTni;PT3OqoK#s^%@t)wrti!eR&ahk%!9hZ8$x$spu2WJuQ4&~wDEACnfKr&w&}TEl~LOY}+AORx45-=}&`f6mZPoZCSnIMHB`>LZD9hK@`dDx2nZ>GN@v;08{xPQ$iMhhJhE)&NHzD{8cjSxYCf zuISMc62bN?f#}tPH8MZ4mZDZI_S^2cl}i~XWlp<`I1iDKpa#{&wjm^RIZqgqv51EG zzzS9*kZQaZjZjL4+C?+S>aShYD8}h6>zebORV%e#;wG)(%{ayMB4_9TA(;A%EgIJsPE

C;Hqo2oHWR-OVf} ztSrG6m)@fEG;u^Y6pt`OD^-xvJhtFoaWP+-;2s-_a($bOGbUhyvqb}BV{*-s%vk(r zi+F~Nf8wngQ!Dw32S;EW&hf~WwLdcnlld~ykIL*XnsVxfLJwmL#@`Z++v4$Q&PfF; zzJyP)PEQzymjlSkt#(UxB8e;bY{MBhIQ$9dh7dnCu8&Dc;7DoCZTiG_)r7V=>e-V7Rtmr@5yd zsHZSi_mwTlS9>FwQn7yfL>jrYmJ@|EcR;2}O2j>IU9wYs3`R@w+yaL{;d^?{O3?UZ z#G5%`Ejh0(;;9SpS)2r6WMUx!2n$6l`T^J~S`#amL(11v>op#*VtkNwTuEk&_$)(( z6mumW2V~(?PDp7nX8kfjXLe*d=ic?c$`1+3C)-;VbhD0@BvjZj% zQFq)QpUlYgXT^;NQCTnTEUuT#pC``mdgwjO%?ZoBj>^ C0VT!& delta 1440 zcmZ`%ZERCz6h5~-x8L7uyRmj~*K89Kbc3yKHMDR?wd=rafeiyhOIK50%73eyH(>Gk#_2X$y4)_v7BvzV|%m z`FPLgJKk$PZq2L*;P(UAJ%De#O7%8i_B=qP7WfV~fO#z_qk{m}H=*Tk1W+x2=j&zw zT`h^mju$)tHaT=YdIG@m1MK^ea0VMpE#CsDsDabZ^3*>fL-9lE^U93R_0jo^ z+`g0p$NXraxcks8V?*QN=U;pqo0LJ-ZwNLY{oo8uIJHK_Xj`%q* zFEu?*j$8QGwbLZzZGPtHb#k8N-=Drk^5%=x{29MEON17gB3k_s5icqdI>PZ;MZ(_; zpxCG6s_471SE;F=Ac8Z>{fAyUm;;Zwf^7&%@3-_vOVOV`$T=C z;|hQ#s$M*Qjt1UVf2$`4nyZ?RF9*r_lIHi5Efn?lTK7$=@*!PdJrP=~bg8Gvq3UVf z&ktP%(9i3`my(o#Nq=K@3*oNlXI(c*a645>6axCWDZ;70GB_JubS1L}=j7%v0s0Ni zr=KAQGlpGBMu680yN+HYLNM%h(g5X`hD-gIiSUC6#S~&2vDvX(N~a_7fs~TwD#ShA zp#h1L({C4AS*^mBJBD7K?brBob-D$fU8p$V(gvisG#rYRTI+Bvis(fjZl?DRbdT3t z*?f(f?X=o-E4$f2YrwMdpulv7U9cT8w_qD?LpMH#?KEf`wy{Qge>wV`-J5v;twI-} zwqTQrM1z7JzGqMxlJb5YXnq6*+)i3WqVZuDwvyUFL9+)065u6rH - + - AVPage + AVForm - - Video Settings + + Audio/Video settings + Настройки аудио/видео + + + + Hide video preview + On a button + Спрятать видео-превью + + + + Show video preview + On a button + Посмотреть видео-превью + + + + AVSettings + + + + Form + + + + + + Video settings Настройки видео - - + + Show video preview - On a button - - - - - Hide video preview - On a button - + Посмотреть видео-превью @@ -27,7 +47,7 @@ Add Friends - Добавление друзей + Добавить друзей @@ -64,12 +84,7 @@ You can't add yourself as a friend! When trying to add your own Tox ID as friend - - - - You can't add yourself as a friend ! - When trying to add your own Tox ID as friend - Нельзя добавить самого себя в друзья! + Вы не можете добавить себя как друга! @@ -109,75 +124,50 @@ Ответ DNS не содержит корректных Tox ID - - Camera - - Camera eror - Ошибка камеры - - - Camera format %1 not supported, can't use the camera - Формат камеры %1 не поддерживается, невозможно использовать камеру - - ChatForm - + Send a file Отправить файл - - Save chat log - Сохранить лог чата - - CopyableElideLabel + Core - Copy - Копировать + + Encrypted profile + Зашифрованный профиль + + + + Your tox profile seems to be encrypted, qTox can't open it +Do you want to erase this profile ? + Похоже, ваш tox-профиль зашифрован, qTox не может открыть его +Вы хотите удалить этот профиль? FileTransferInstance - + Save a file Title of the file saving dialog Сохранить файл - + Location not writable Title of permissions popup Непригодная для записи локация - + You do not have permission to write that location. Choose another, or cancel the save dialog. text of permissions popup У вас нет прав записи в эту локацию. Выберете другую или закройте диалог сохранения. - - FileTransfertWidget - - Save a file - Title of the file saving dialog - Сохранить файл - - - Location not writable - Title of permissions popup - Непригодная для записи локация - - - You do not have permission to write that location. Choose another, or cancel the save dialog. - text of permissions popup - У вас нет прав записи в эту локацию. Выберете другую или закройте диалог сохранения. - - FilesForm @@ -238,71 +228,138 @@ FriendWidget - + Copy friend ID Menu to copy the Tox ID of that friend Копировать ID друга - + Invite in group Menu to invite a friend in a groupchat Пригласить в группу - + Remove friend Menu to remove the friend from our friendlist Удалить друга - GeneralPage + GeneralForm - + General Settings - Основные настройки + Общие настройки - + + Bad port + title of bad port popup + Неправильный порт + + + + The port you entered is invalid; please enter another. + text of bad port popup + Введёный порт неверен; введите другой. + + + + GeneralSettings + + + + Form + + + + + + General Settings + Общие настройки + + + + Enable IPv6 (recommended) - Text on a checkbox to enable IPv6 + Text on a checkbox to enable IPv6 Включить IPv6 (рекомендуется) - + + Use translations - Text on a checkbox to enable translations - Русскоязычный интерфейс + Text on a checkbox to enable translations + Использовать перевод - + + + Save settings to the working directory instead of the usual conf dir + describes makeToxPortable checkbox + Сохранять настройки в рабочую директорию вместо страндартной папки настроек + + + + Make Tox portable - Text on a checkbox to make qTox a portable application Портативный режим - - Save settings to the working directory instead of the usual conf dir - describes makeToxPortable checkbox - Сохранять настройки в рабочую директорию вместо страндартной директории настроек - - - + + Theme Тема - + + Smiley Pack + Text on smiley pack label Набор смайликов + + + + Proxy settings + Настройки прокси + + + + + Disable UDP (not recommended) + Text on checkbox to disable UDP + Выключить UDP (не рекомендуется) + + + + + This allows, e.g., toxing over Tor. It adds load to the Tox network however, so use only when necessary. + force tcp checkbox tooltip + Это позволяет, например, использовать tox поверх Tor. Однако это добавляет нагрузку на сеть Tox, так что используйте только в случае необходимости. + + + + + Proxy address + Text on proxy addr label + Адрес прокси + + + + + Proxy port + Text on proxy port label + Порт прокси + GenericChatForm - - + + Save chat log Сохранить лог чата @@ -310,125 +367,150 @@ GroupChatForm - + %1 users in chat Number of users in chat %1 пользователей в чате - - <Unknown> - <Неизвестно> - - - + %1 users in chat %1 пользователей в чате - - Save chat log - Сохранить лог чата - GroupWidget - + Quit group Menu to quit a groupchat Покинуть группу - - + + %1 users in chat %1 пользователей в чате - - + + 0 users in chat Ни одного пользователя в чате - IdentityPage + IdentityForm - + + Your identity + Ваша идентификация + + + + IdentitySettings + + + + Form + + + + + Public Information Публичные данные - + + Name - Username/nick Имя - + + Status - Status message Статус - + + Tox ID Tox ID - - Your Tox ID - Ваш Tox ID + + + Your Tox ID (click to copy) + Ваш Tox ID (нажмите на него, чтобы скопировать) MainWindow + qTox qTox - + + Your name Ваше имя - + + Your status Ваш статус - + + Add friends Добавить друзей - + + Create a group chat Создать групповой чат - + + View completed file transfers Завершённые файлопередачи - + + Change your settings Изменить ваши настройки - + + Close Закрыть - + + Ctrl+Q Ctrl+Q + + PrivacyForm + + + Privacy settings + Настройки приватности + + SelfCamView @@ -438,166 +520,67 @@ Проверка видео - - SettingsDialog - - Settings Dialog - Диалог настроек - - - - qTox – Settings - - - - - General - Основное - - - - Identity - Личные данные - - - - Privacy - Безопасность - - - - Audio/Video - Аудио и видео - - - - Ok - ОК - - - - Cancel - Отмена - - - - Apply - Применить - - - - SettingsForm - - User Settings - "Headline" of the window - Пользовательские настройки - - - Name - Username/nick - Имя - - - Status - Status message - Статус - - - (click here to copy) - Click on this text to copy TID to clipboard - (нажмите здесь чтобы скопировать) - - - Test video - Text on a button to test the video/webcam - Проверить видео - - - Enable IPv6 (recommended) - Text on a checkbox to enable IPv6 - Включить IPv6 (рекомендуется) - - - Use translations - Text on a checkbox to enable translations - Так гораздо понятнее, чем «использовать переводы» - Русскоязычный интерфейс - - - Make Tox portable - Text on a checkbox to make qTox a portable application - Портативный режим - - - Save settings to the working directory instead of the usual conf dir - describes makeToxPortable checkbox - Сохранять настройки в рабочую директорию вместо страндартной директории настроек - - - Smiley Pack - Text on smiley pack label - Набор смайликов - - Widget - Tox - Tox - - - Your name - Ваше имя - - - Your status - Ваш статус - - - Add friends - Добавить друзей - - - Create a group chat - Создать групповой чат - - - (button inactive currently) - (кнопка на данный момент неактивна) - - - Change your settings - Изменить ваши настройки - - - Close - Закрыть - - - Ctrl+Q - Ctrl+Q - - - + Online Button to set your status to 'Online' В сети - + Away Button to set your status to 'Away' Вероятно, это не столь долгое путешествие Отошёл - + Busy Button to set your status to 'Busy' Занят - + + Choose a profile picture + Выбрать картинку для профиля + + + + + + Error + Ошибка + + + + Unable to open this file + Невозможно открыть файл + + + + Unable to read this image + Невозможно прочесть это изображение + + + + This image is too big + Это изображение слишком большое + + + + Toxcore failed to start, the application will terminate after you close this message. + Не удалось запустить toxcore, приложение будет завершено после того как вы закроете это сообщение. + + + + toxcore failed to start with your proxy settings. qTox cannot run; please modify your settings and restart. + popup text + Не удалось запустить toxcore с вашими настройками прокси, qTox не может работать; измените ваши настройки и перезапустите его. + + + <Unknown> Placeholder when we don't know someone's name in a group chat <Неизвестно> From ddf7a7edfd897f0731a0fbf31af718e09fd601f3 Mon Sep 17 00:00:00 2001 From: apprb Date: Tue, 7 Oct 2014 11:09:15 +0900 Subject: [PATCH 191/205] added "Use Proxy" checkbox --- core.cpp | 46 ++++++++++++++----------- misc/settings.cpp | 11 ++++++ misc/settings.h | 5 +++ widget/form/settings/generalform.cpp | 32 ++++++++++------- widget/form/settings/generalform.h | 3 +- widget/form/settings/generalsettings.ui | 44 +++++++++++++---------- 6 files changed, 89 insertions(+), 52 deletions(-) diff --git a/core.cpp b/core.cpp index ea83116b8..dd8445dee 100644 --- a/core.cpp +++ b/core.cpp @@ -122,8 +122,9 @@ void Core::start() // IPv6 needed for LAN discovery, but can crash some weird routers. On by default, can be disabled in options. bool enableIPv6 = Settings::getInstance().getEnableIPv6(); bool forceTCP = Settings::getInstance().getForceTCP(); - QString proxyAddr = Settings::getInstance().getProxyAddr(); - int proxyPort = Settings::getInstance().getProxyPort(); + + bool useProxy = Settings::getInstance().getUseProxy(); + if (enableIPv6) qDebug() << "Core starting with IPv6 enabled"; else @@ -132,26 +133,29 @@ void Core::start() Tox_Options toxOptions; toxOptions.ipv6enabled = enableIPv6; toxOptions.udp_disabled = forceTCP; - if (proxyAddr.length() > 255) + + // No proxy by default + toxOptions.proxy_enabled = false; + toxOptions.proxy_address[0] = 0; + toxOptions.proxy_port = 0; + + if (useProxy) { - qWarning() << "Core: proxy address" << proxyAddr << "is too long"; - toxOptions.proxy_enabled = false; - toxOptions.proxy_address[0] = 0; - toxOptions.proxy_port = 0; - } - else if (proxyAddr != "" && proxyPort > 0) - { - qDebug() << "Core: using proxy" << proxyAddr << ":" << proxyPort; - toxOptions.proxy_enabled = true; - uint16_t sz = CString::fromString(proxyAddr, (unsigned char*)toxOptions.proxy_address); - toxOptions.proxy_address[sz] = 0; - toxOptions.proxy_port = proxyPort; - } - else - { - toxOptions.proxy_enabled = false; - toxOptions.proxy_address[0] = 0; - toxOptions.proxy_port = 0; + QString proxyAddr = Settings::getInstance().getProxyAddr(); + int proxyPort = Settings::getInstance().getProxyPort(); + + if (proxyAddr.length() > 255) + { + qWarning() << "Core: proxy address" << proxyAddr << "is too long"; + } + else if (proxyAddr != "" && proxyPort > 0) + { + qDebug() << "Core: using proxy" << proxyAddr << ":" << proxyPort; + toxOptions.proxy_enabled = true; + uint16_t sz = CString::fromString(proxyAddr, (unsigned char*)toxOptions.proxy_address); + toxOptions.proxy_address[sz] = 0; + toxOptions.proxy_port = proxyPort; + } } tox = tox_new(&toxOptions); diff --git a/misc/settings.cpp b/misc/settings.cpp index b3af2144d..8e4df9f02 100644 --- a/misc/settings.cpp +++ b/misc/settings.cpp @@ -141,6 +141,7 @@ void Settings::load() s.beginGroup("Privacy"); typingNotification = s.value("typingNotification", false).toBool(); forceTCP = s.value("forceTCP", false).toBool(); + useProxy = s.value("useProxy", false).toBool(); proxyAddr = s.value("proxyAddr", "").toString(); proxyPort = s.value("proxyPort", 0).toInt(); s.endGroup(); @@ -242,6 +243,7 @@ void Settings::save(QString path) s.beginGroup("Privacy"); s.setValue("typingNotification", typingNotification); + s.setValue("useProxy", useProxy); s.setValue("forceTCP", forceTCP); s.setValue("proxyAddr", proxyAddr); s.setValue("proxyPort", proxyPort); @@ -367,6 +369,15 @@ void Settings::setForceTCP(bool newValue) forceTCP = newValue; } +bool Settings::getUseProxy() const +{ + return useProxy; +} +void Settings::setUseProxy(bool newValue) +{ + useProxy = newValue; +} + QString Settings::getProxyAddr() const { return proxyAddr; diff --git a/misc/settings.h b/misc/settings.h index 82f6e3872..7c43987d6 100644 --- a/misc/settings.h +++ b/misc/settings.h @@ -58,6 +58,9 @@ public: QString getProxyAddr() const; void setProxyAddr(const QString& newValue); + bool getUseProxy() const; + void setUseProxy(bool newValue); + int getProxyPort() const; void setProxyPort(int newValue); @@ -164,6 +167,8 @@ private: static bool makeToxPortable; bool forceTCP; + + bool useProxy; QString proxyAddr; int proxyPort; diff --git a/widget/form/settings/generalform.cpp b/widget/form/settings/generalform.cpp index e998a9f5f..b8138874e 100644 --- a/widget/form/settings/generalform.cpp +++ b/widget/form/settings/generalform.cpp @@ -42,7 +42,10 @@ GeneralForm::GeneralForm() : bodyUI->proxyAddr->setText(Settings::getInstance().getProxyAddr()); int port = Settings::getInstance().getProxyPort(); if (port != -1) - bodyUI->proxyPort->setText(QString::number(port)); + bodyUI->proxyPort->setValue(port); + + bodyUI->cbUseProxy->setChecked(Settings::getInstance().getUseProxy()); + onUseProxyUpdated(); connect(bodyUI->cbEnableIPv6, &QCheckBox::stateChanged, this, &GeneralForm::onEnableIPv6Updated); connect(bodyUI->cbUseTranslations, &QCheckBox::stateChanged, this, &GeneralForm::onUseTranslationUpdated); @@ -51,7 +54,8 @@ GeneralForm::GeneralForm() : // new syntax can't handle overloaded signals... (at least not in a pretty way) connect(bodyUI->cbUDPDisabled, &QCheckBox::stateChanged, this, &GeneralForm::onUDPUpdated); connect(bodyUI->proxyAddr, &QLineEdit::editingFinished, this, &GeneralForm::onProxyAddrEdited); - connect(bodyUI->proxyPort, &QLineEdit::editingFinished, this, &GeneralForm::onProxyPortEdited); + connect(bodyUI->proxyPort, SIGNAL(valueChanged(int)), this, SLOT(onProxyPortEdited(int))); + connect(bodyUI->cbUseProxy, &QCheckBox::stateChanged, this, &GeneralForm::onUseProxyUpdated); } GeneralForm::~GeneralForm() @@ -90,17 +94,21 @@ void GeneralForm::onProxyAddrEdited() Settings::getInstance().setProxyAddr(bodyUI->proxyAddr->text()); } -void GeneralForm::onProxyPortEdited() +void GeneralForm::onProxyPortEdited(int port) { - QString text = bodyUI->proxyPort->text(); - if (text != "") + if (port > 0) { - int port = text.toInt(); - if (port < 1) - QMessageBox::warning(bodyUI->proxyPort, tr("Bad port", "title of bad port popup"), tr("The port you entered is invalid; please enter another.", "text of bad port popup")); - else - Settings::getInstance().setProxyPort(port); - } - else + Settings::getInstance().setProxyPort(port); + } else { Settings::getInstance().setProxyPort(-1); + } +} + +void GeneralForm::onUseProxyUpdated() +{ + bool state = bodyUI->cbUseProxy->isChecked(); + + bodyUI->proxyAddr->setEnabled(state); + bodyUI->proxyPort->setEnabled(state); + Settings::getInstance().setUseProxy(state); } diff --git a/widget/form/settings/generalform.h b/widget/form/settings/generalform.h index 2af8f4bb6..ddfde9522 100644 --- a/widget/form/settings/generalform.h +++ b/widget/form/settings/generalform.h @@ -39,7 +39,8 @@ private slots: void onSmileyBrowserIndexChanged(int index); void onUDPUpdated(); void onProxyAddrEdited(); - void onProxyPortEdited(); + void onProxyPortEdited(int port); + void onUseProxyUpdated(); private: Ui::GeneralSettings *bodyUI; diff --git a/widget/form/settings/generalsettings.ui b/widget/form/settings/generalsettings.ui index 7057866a8..fff913ef4 100644 --- a/widget/form/settings/generalsettings.ui +++ b/widget/form/settings/generalsettings.ui @@ -15,13 +15,13 @@ - 15 + 6 - 15 + 6 - 15 + 6 @@ -83,40 +83,48 @@ - - Disable UDP (not recommended) - This allows, e.g., toxing over Tor. It adds load to the Tox network however, so use only when necessary. + + Disable UDP (not recommended) + - + + + Use proxy (SOCKS5) + + + + + - Proxy address + Address + + + - Proxy port + Port - - - - - - - - - + + + 0 + + + 65535 + From f5c619465675dc4ff0ec35c734a4aed5069dd442 Mon Sep 17 00:00:00 2001 From: apprb Date: Tue, 7 Oct 2014 11:11:40 +0900 Subject: [PATCH 192/205] Introduced "Connection Settings" group in GeneralSettings widget --- widget/form/settings/generalsettings.ui | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/widget/form/settings/generalsettings.ui b/widget/form/settings/generalsettings.ui index fff913ef4..653f15204 100644 --- a/widget/form/settings/generalsettings.ui +++ b/widget/form/settings/generalsettings.ui @@ -29,13 +29,6 @@ General Settings - - - - Enable IPv6 (recommended) - - - @@ -76,11 +69,18 @@ - + - Proxy settings + Connection Settings + + + + Enable IPv6 (recommended) + + + From 443ee0a4f864bb5862c1536aecf50616013ef518 Mon Sep 17 00:00:00 2001 From: apprb Date: Tue, 7 Oct 2014 11:16:06 +0900 Subject: [PATCH 193/205] Proxy settings is more close to General group in settings.ini than to Privacy --- misc/settings.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/misc/settings.cpp b/misc/settings.cpp index 8e4df9f02..545684272 100644 --- a/misc/settings.cpp +++ b/misc/settings.cpp @@ -110,6 +110,10 @@ void Settings::load() enableIPv6 = s.value("enableIPv6", true).toBool(); useTranslations = s.value("useTranslations", true).toBool(); makeToxPortable = s.value("makeToxPortable", false).toBool(); + forceTCP = s.value("forceTCP", false).toBool(); + useProxy = s.value("useProxy", false).toBool(); + proxyAddr = s.value("proxyAddr", "").toString(); + proxyPort = s.value("proxyPort", 0).toInt(); s.endGroup(); s.beginGroup("Widgets"); @@ -140,10 +144,6 @@ void Settings::load() s.beginGroup("Privacy"); typingNotification = s.value("typingNotification", false).toBool(); - forceTCP = s.value("forceTCP", false).toBool(); - useProxy = s.value("useProxy", false).toBool(); - proxyAddr = s.value("proxyAddr", "").toString(); - proxyPort = s.value("proxyPort", 0).toInt(); s.endGroup(); // try to set a smiley pack if none is selected @@ -213,6 +213,10 @@ void Settings::save(QString path) s.setValue("enableIPv6", enableIPv6); s.setValue("useTranslations",useTranslations); s.setValue("makeToxPortable",makeToxPortable); + s.setValue("useProxy", useProxy); + s.setValue("forceTCP", forceTCP); + s.setValue("proxyAddr", proxyAddr); + s.setValue("proxyPort", proxyPort); s.endGroup(); s.beginGroup("Widgets"); @@ -243,10 +247,6 @@ void Settings::save(QString path) s.beginGroup("Privacy"); s.setValue("typingNotification", typingNotification); - s.setValue("useProxy", useProxy); - s.setValue("forceTCP", forceTCP); - s.setValue("proxyAddr", proxyAddr); - s.setValue("proxyPort", proxyPort); s.endGroup(); } From 1fdc98873bbb29a041ec5bf591e6899a37ea3f24 Mon Sep 17 00:00:00 2001 From: apprb Date: Tue, 7 Oct 2014 16:12:05 +0900 Subject: [PATCH 194/205] reimplemented insert chat line function: every line in own table --- widget/chatareawidget.cpp | 59 ++++++++++++++++++++++++--------------- widget/chatareawidget.h | 3 +- 2 files changed, 38 insertions(+), 24 deletions(-) diff --git a/widget/chatareawidget.cpp b/widget/chatareawidget.cpp index d3d326b63..c2d4e1a81 100644 --- a/widget/chatareawidget.cpp +++ b/widget/chatareawidget.cpp @@ -26,6 +26,7 @@ ChatAreaWidget::ChatAreaWidget(QWidget *parent) : QTextBrowser(parent) , nameWidth(75) + , tableFrmt(nullptr) { setReadOnly(true); viewport()->setCursor(Qt::ArrowCursor); @@ -37,15 +38,6 @@ ChatAreaWidget::ChatAreaWidget(QWidget *parent) setAcceptRichText(false); setFrameStyle(QFrame::NoFrame); - QTextTableFormat tableFormat; - tableFormat.setCellSpacing(5); - tableFormat.setBorderStyle(QTextFrameFormat::BorderStyle_None); - tableFormat.setColumnWidthConstraints({QTextLength(QTextLength::FixedLength,nameWidth), - QTextLength(QTextLength::PercentageLength,100), - QTextLength(QTextLength::VariableLength,0)}); - - chatTextTable = textCursor().insertTable(1,3,tableFormat); - nameFormat.setAlignment(Qt::AlignRight); nameFormat.setNonBreakableLines(true); dateFormat.setAlignment(Qt::AlignLeft); @@ -60,6 +52,9 @@ ChatAreaWidget::~ChatAreaWidget() for (ChatAction* action : messages) delete action; messages.clear(); + + if (tableFrmt) + delete tableFrmt; } void ChatAreaWidget::mouseReleaseEvent(QMouseEvent * event) @@ -108,16 +103,15 @@ void ChatAreaWidget::insertMessage(ChatAction *msgAction) checkSlider(); - int row = chatTextTable->rows() - 1; - QTextCursor cur = chatTextTable->cellAt(row,1).firstCursorPosition(); + QTextTable *chatTextTable = getMsgTable(); + QTextCursor cur = chatTextTable->cellAt(0, 1).firstCursorPosition(); cur.clearSelection(); cur.setKeepPositionOnInsert(true); - chatTextTable->appendRows(1); - chatTextTable->cellAt(row,0).firstCursorPosition().setBlockFormat(nameFormat); - chatTextTable->cellAt(row,0).firstCursorPosition().insertHtml(msgAction->getName()); - chatTextTable->cellAt(row,1).firstCursorPosition().insertHtml(msgAction->getMessage()); - chatTextTable->cellAt(row,2).firstCursorPosition().setBlockFormat(dateFormat); - chatTextTable->cellAt(row,2).firstCursorPosition().insertHtml(msgAction->getDate()); + chatTextTable->cellAt(0, 0).firstCursorPosition().setBlockFormat(nameFormat); + chatTextTable->cellAt(0, 0).firstCursorPosition().insertHtml(msgAction->getName()); + chatTextTable->cellAt(0, 2).firstCursorPosition().insertHtml(msgAction->getMessage()); + chatTextTable->cellAt(0, 4).firstCursorPosition().setBlockFormat(dateFormat); + chatTextTable->cellAt(0, 4).firstCursorPosition().insertHtml(msgAction->getDate()); msgAction->setup(cur, this); @@ -137,13 +131,32 @@ void ChatAreaWidget::checkSlider() lockSliderToBottom = scroll && scroll->value() == scroll->maximum(); } +QTextTable *ChatAreaWidget::getMsgTable() +{ + if (tableFrmt == nullptr) + { + tableFrmt = new QTextTableFormat(); + tableFrmt->setCellSpacing(2); + tableFrmt->setBorderStyle(QTextFrameFormat::BorderStyle_None); + tableFrmt->setColumnWidthConstraints({QTextLength(QTextLength::FixedLength,nameWidth), + QTextLength(QTextLength::FixedLength,2), + QTextLength(QTextLength::PercentageLength,100), + QTextLength(QTextLength::FixedLength,2), + QTextLength(QTextLength::VariableLength,0)}); + } + + QTextTable *chatTextTable = textCursor().insertTable(1, 5, *tableFrmt); + + return chatTextTable; +} + void ChatAreaWidget::setNameColWidth(int w) { - nameWidth = w; + if (tableFrmt != nullptr) + { + delete tableFrmt; + tableFrmt = nullptr; + } - QTextTableFormat tableFormat = chatTextTable->format(); - tableFormat.setColumnWidthConstraints({QTextLength(QTextLength::FixedLength, 100), - QTextLength(QTextLength::PercentageLength, 100), - QTextLength(QTextLength::FixedLength, 40)}); - chatTextTable->setFormat(tableFormat); + nameWidth = w; } diff --git a/widget/chatareawidget.h b/widget/chatareawidget.h index 05d41de4e..d1e2dbe8f 100644 --- a/widget/chatareawidget.h +++ b/widget/chatareawidget.h @@ -46,12 +46,13 @@ private slots: private: void checkSlider(); + QTextTable* getMsgTable(); + QTextTableFormat* tableFrmt; QList messages; bool lockSliderToBottom; int sliderPosition; int nameWidth; - QTextTable *chatTextTable; QTextBlockFormat nameFormat, dateFormat; }; From 7a7076eb192d16f03a9c2efa0eb614b81d35155e Mon Sep 17 00:00:00 2001 From: Ansa89 Date: Tue, 7 Oct 2014 11:06:54 +0200 Subject: [PATCH 195/205] Italian translation: update --- translations/it.qm | Bin 7641 -> 9978 bytes translations/it.ts | 313 +++++++++++++++++++++++++++------------------ 2 files changed, 190 insertions(+), 123 deletions(-) diff --git a/translations/it.qm b/translations/it.qm index 179823b08a782188749dffc9c18478eb15acdf03..a0899636248de8e86218d7e41c0bb5feb7b326b1 100644 GIT binary patch delta 3620 zcmaJ@Yiu0V6+Uav`nkJ)UjnB|sGdZGL9-#gytQ7;a zqwmK=?Je}cu`&30g&zI~>}8uxI)42kHn!6X`+`J`SLwYS4jg<==YMz!ihXqT+-F41 zXUginsX_09@)g(eM1e=k2iv|N3U`#BeeQciW!dsehyRU0%9O$P;pn!t%0kIi@_n1XM(>zd66iX_12Z|2QQ75 z1A#LYlPli_a$l>kLO53ys;~w|h-z-F475C(MI_P6n$^$2!M7?W>?T0?TID+%{|m*T z%Cnz72_(K>6?o#iMCC`S9=}*gB$TRC7kZH*st)fz5698!=I8%HRB2ToI57;pb=B`~ zf1N0jtp51rm!S1g^&j$Y!QRp8KZS9@$m!}EHUhcr)0(+!*|mu5J2jsl*@zr{SgUL| zVDNhFrVDruhC=suBhrqYA!qj$Kp6{NUGp2HVqG|XI*mXZ!udl;&8pqu->$kq)Rw}E z6a;<|K6@PJ!hemluU|#fR2OMK8i&3X>3v}@ZoV(FE1iS>naHl#Q?J5NKJrjI4Ag!Y zIX(U>Kpurv9n8VXYrE;<_aq-E|Ff!U23#(LZ{hWv2qH-a_}0PBx`-FP8O&7KmfH z&&sxJE()rkXR%%t4p9ZZ3h%MGn*Py;3f2oI`D|Z9sl1CL+b~K7#o^K_8j389aKX|1 zW92VZWCg|G+@f)uPGS|L;n|=xxuoJdZ>`~8Q?oN^SC5OdZH*gAonut)v20yN_a+U( zg20(6X(wG`cNo%H>^q1tMPt}iNo4WhNRf?yOPo^=Wc$fKYQlsGNg6Kxg;m8r4%U{T zKZ3nc>D<7c4w(T*2Ba!9*!q6#vOio)TCpiRfAeic-1hFVrflI_v;IYqWIg3TBF1!~ z`!Mu~{ln1FRCA3hth8t*xM8=vDGpgybzHY0IF5HCS6m4x=2wU#%_Llsnn)AWI zJ7@^er4S#dgYU?!;3V)}Yc$_Z=*#qrw1?e<27~nX<+$ycGmH>}bnr2u%#2J0xfCFmr zGdq~V%K1yeEZ;X;1ix=Mq04(o9Cg#xZ7>e_8RoQ_G~!!DI;k_La!aVDjA34r71&U@)`1p?>hqh7}jp=c~oQAHGC|jMujwvUq)hWG2o5? z!%@eQx)>RViEe}=Y`s&nQYqbx>+!W5SY07Kel_R5tW)nU70M#INjE6fN1li3mk8gh z-_N7qIyX2z$wW8s%RHXI$DrIJ)m7-Inlxib)_5fMDveEh4n5;u zbDP3J=GA-%ULSUVy#J4b~Nepw3QIpB6HRJRMJvtHX;TDF`B&=!O z7Q>bu6@xCP+!09&%>(TTrGt%GVe0OTWlxHPHKRkhM>v+4LXBBwG9zXZXl55*>S zld7oqmHpZ(l+h5-L5hpSQ-;)(99Sg>$|jtg)x4{rL=5Tq=B{O=H=6IrF42`fH=t{1 zvd3`0U|R6F;jE^SHSUc}r8FcS$>uvqn}mS#FgPH(wWOgkSLM_YEfKxU8r9zQu= zevT54*7-5a9OeS@nz>DX#@%=h@Fd||dNYK}gS#gqz%oM?7;7vZ!(50?N|M^EqJ^{` z0V*2aFvPfu7Y@l;$5m|?+y-^kbQ)l(u3?#C#z-awhDFLSRTo?1_%BC@mbCm4oMH-3 z=+WHO_A5cWqy@f?tFOP=)xD(gtV$wG`ErxHyrM13|BKyi2|)hv@ZVF$adnd(0|Y!& z{2t@M>oo=LCJclr8w587pETY;_2+2{7SJjxuFdmL*Z_~c>4{BXPqD5gv>$; z=G6uLViLV!IbeaKn_%2*eqq6g@LP4X__iZQ+>}`u#C^I*S#e`L;~nzVF__~RgfdyO TWmN1o;uE?XIDiT-3k3cTAOnBX delta 1483 zcmZ`%du&s66#i~|Z*OlOcaN^6uSqw?=07|XkTj4$<6tchJ4c0}2CeIL>(=!}I~e~I zgM{fcY+jMQk|oMW27e6gVxp305XZ8Zso6#(#0Si%7!qP!RLD?IJ89O1<(KC4o^!tM zob#P?Z}+uLoh7L#z&!^n`wi@yuL0&6u>C`Tr4XEZ15o@C_~u5yH(uiAyrLM13Q(b*))K6l^)wYDtJRVe)>4TTvATI^#>q~vYt^YWR0X^6YL2l!Y_lU^CZE38a!uL68?KbN8NA3;n89>{_o$L4k?Lp2UgsGz#fu!gX60$(Z{a(y+)dHM27dgP zVKNTXjLqZ%a@WX+q zd|c^}UsPJmwf+W)$!5TXR(io)f>VGQguIC-Mvd7ZXK3QKW+C=-&Kj8Ek|#*Dl39O++8B9rHlRp!T>3rVtl zs^OzSXbg2`Ko$KsU!&9_W%^i{EYDfod30%?bp<0IDSKQF*yiNxcAH-32}t2YFwvIn zkT0!UlaSsibg|i8KC$;=IWq76lutoGs$-q%TrocG7yZc$u485%nW~+ zUXm(=7VxW{^oQ%E&{D8M)R4sC?7jF2DCMN)|6eH&%fovUQ7gyn#+3Sjv`f`s;l<7z zufp5BR3b6b*#_w{{iIP_4#L;QgRTDhhpSXf(p4fxrxL+o+RQ3A=z`6wbLgU2W;r*H Z%6WIZNbPj8>>EZtP%+836Q6=%{sR@-dwl=^ diff --git a/translations/it.ts b/translations/it.ts index 96f3de1de..3740103da 100644 --- a/translations/it.ts +++ b/translations/it.ts @@ -2,24 +2,41 @@ - AVPage + AVForm - - Video Settings - Impostazioni Webcam + + Audio/Video settings + Impostazioni Audio/Video - - - Show video preview - On a button - Avvia prova webcam - - - + Hide video preview On a button - Ferma prova webcam + Ferma webcam + + + + Show video preview + On a button + Prova webcam + + + + AVSettings + + + Form + Form + + + + Video settings + Impostazioni Video + + + + Show video preview + Prova webcam @@ -105,27 +122,41 @@ ChatForm - + Send a file Invia un file + + Core + + + Encrypted profile + Profilo criptato + + + + Your tox profile seems to be encrypted, qTox can't open it +Do you want to erase this profile ? + Il tuo profilo Tox sembra essere criptato, qTox non può aprirlo\nVuoi eliminare questo profilo? + + FileTransferInstance - + Save a file Title of the file saving dialog Salva file - + Location not writable Title of permissions popup Errore - + You do not have permission to write that location. Choose another, or cancel the save dialog. text of permissions popup Non hai sufficienti permessi per scrivere in questa locazione. Scegli un'altra posizione, o annulla il salvataggio. @@ -189,71 +220,125 @@ FriendWidget - + Copy friend ID Menu to copy the Tox ID of that friend Copia Tox ID del contatto - + Invite in group Menu to invite a friend in a groupchat Invita nel gruppo - + Remove friend Menu to remove the friend from our friendlist Rimuovi contatto - GeneralPage + GeneralForm - + General Settings Impostazioni Generali - + + Bad port + title of bad port popup + Numero porta errato + + + + The port you entered is invalid; please enter another. + text of bad port popup + Il numero della porta che hai inserito è invalido; per favore inseriscine un altro. + + + + GeneralSettings + + + Form + Form + + + + General Settings + Impostazioni Generali + + + Enable IPv6 (recommended) - Text on a checkbox to enable IPv6 + Text on a checkbox to enable IPv6 Abilita IPv6 (consigliato) - + Use translations - Text on a checkbox to enable translations + Text on a checkbox to enable translations Abilita traduzioni - - Make Tox portable - Text on a checkbox to make qTox a portable application - Rendi qTox portabile - - - + Save settings to the working directory instead of the usual conf dir - describes makeToxPortable checkbox + describes makeToxPortable checkbox Slava le impostazioni nella directory di lavoro corrente, invece della directory di default - - Theme - Tema + + Make Tox portable + Rendi qTox portabile - + + Theme + Impostazioni tema + + + Smiley Pack + Text on smiley pack label Emoticons + + + Proxy settings + Impostazioni proxy + + + + Disable UDP (not recommended) + Text on checkbox to disable UDP + Disabilita connessioni UDP (non raccomandato) + + + + This allows, e.g., toxing over Tor. It adds load to the Tox network however, so use only when necessary. + force tcp checkbox tooltip + Questo permette di usare qTox con Tor; tuttavia aggiunge carico alla rete Tox, quindi usalo solo se necessario. + + + + Proxy address + Text on proxy addr label + IP + + + + Proxy port + Text on proxy port label + Porta + GenericChatForm - + Save chat log Salva il log della chat @@ -261,18 +346,13 @@ GroupChatForm - + %1 users in chat Number of users in chat %1 utenti in chat - - <Unknown> - <Sconosciuto> - - - + %1 users in chat %1 utenti in chat @@ -280,52 +360,63 @@ GroupWidget - - + + %1 users in chat %1 utenti in chat - - + + 0 users in chat 0 utenti in chat - + Quit group Menu to quit a groupchat Esci dal gruppo - IdentityPage + IdentityForm - + + Your identity + Il tuo profilo + + + + IdentitySettings + + + Form + Form + + + Public Information Informazioni Pubbliche - + Name - Username/nick Nome - + Status - Status message Stato - + Tox ID Tox ID - - Your Tox ID - Il tuo Tox ID + + Your Tox ID (click to copy) + (clicca qui per copiare) @@ -336,46 +427,54 @@ qTox - + Your name qTox User - + Your status Toxing on qTox - + Add friends Aggiungi contatto - + Create a group chat Crea un gruppo - + View completed file transfers Visualizza i trasferimenti completati - + Change your settings Cambia le impostazioni - + Close Chiudi - + Ctrl+Q Ctrl+Q + + PrivacyForm + + + Privacy settings + Impostazioni privacy + + SelfCamView @@ -385,98 +484,66 @@ qTox video test - - SettingsDialog - - - qTox – Settings - qTox - Impostazioni - - - - General - Generale - - - - Identity - Profilo - - - - Privacy - Privacy - - - - Audio/Video - Audio/Video - - - - Ok - OK - - - - Cancel - Annulla - - - - Apply - Applica - - Widget - + Online Button to set your status to 'Online' Online - + Away Button to set your status to 'Away' Assente - + Busy Button to set your status to 'Busy' Occupato - + Choose a profile picture Scegli un'immagine per il profilo - - - + + + Error Errore - + Unable to open this file Impossibile aprire il file - + Unable to read this image Impossibile leggere l'immagine - + This image is too big L'immagine è troppo grande - + + Toxcore failed to start, the application will terminate after you close this message. + Impossibile avviare Toxcore.\nqTox terminerà dopo che avrai chiuso questo messaggio. + + + + toxcore failed to start with your proxy settings. qTox cannot run; please modify your settings and restart. + popup text + Impossibile avviare Toxcore con le tue impostazione proxy.\nqTox non può funzionare correttamente, per favore modifica le impostazioni e riavvia il programma. + + + <Unknown> Placeholder when we don't know someone's name in a group chat <Sconosciuto> From 57c7734c48f080a25c2b40ec2c477e3660bbc16a Mon Sep 17 00:00:00 2001 From: apprb Date: Tue, 7 Oct 2014 19:20:53 +0900 Subject: [PATCH 196/205] bug in file transfer widget displaying fix --- widget/chatareawidget.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/widget/chatareawidget.cpp b/widget/chatareawidget.cpp index c2d4e1a81..2ce9fc267 100644 --- a/widget/chatareawidget.cpp +++ b/widget/chatareawidget.cpp @@ -25,8 +25,8 @@ ChatAreaWidget::ChatAreaWidget(QWidget *parent) : QTextBrowser(parent) - , nameWidth(75) , tableFrmt(nullptr) + , nameWidth(75) { setReadOnly(true); viewport()->setCursor(Qt::ArrowCursor); @@ -104,7 +104,7 @@ void ChatAreaWidget::insertMessage(ChatAction *msgAction) checkSlider(); QTextTable *chatTextTable = getMsgTable(); - QTextCursor cur = chatTextTable->cellAt(0, 1).firstCursorPosition(); + QTextCursor cur = chatTextTable->cellAt(0, 2).firstCursorPosition(); cur.clearSelection(); cur.setKeepPositionOnInsert(true); chatTextTable->cellAt(0, 0).firstCursorPosition().setBlockFormat(nameFormat); @@ -145,7 +145,9 @@ QTextTable *ChatAreaWidget::getMsgTable() QTextLength(QTextLength::VariableLength,0)}); } - QTextTable *chatTextTable = textCursor().insertTable(1, 5, *tableFrmt); + QTextCursor tc = textCursor(); + tc.movePosition(QTextCursor::End); + QTextTable *chatTextTable = tc.insertTable(1, 5, *tableFrmt); return chatTextTable; } From 938325bd2adb2d406004777c595d92d8b824e98f Mon Sep 17 00:00:00 2001 From: Ansa89 Date: Tue, 7 Oct 2014 14:54:58 +0200 Subject: [PATCH 197/205] Italian translation: update --- translations/it.qm | Bin 9978 -> 9735 bytes translations/it.ts | 69 ++++++++++++++++++++------------------------- 2 files changed, 31 insertions(+), 38 deletions(-) diff --git a/translations/it.qm b/translations/it.qm index a0899636248de8e86218d7e41c0bb5feb7b326b1..ace34002bc8dd7b4c0a410d0ea70ce2a3a976cd7 100644 GIT binary patch delta 828 zcmX|9Ye*DP7(JsiJKOHetgGwlx?67MYXeL0QC48GM!r(fEDB6gH#Ec9)Iy2a%Akiz z*5q3dNraMoun|!~f=Hp^A2oPMa=J=Me;mh`NylJA&)OWY-CT^m5{?A-Vlu0i1`#oHbDoIV z@V@>^#5zCS=`s>{e|s|8Wo=^{dh5upk?p)rV;H?Y3>jv-Q>YFFJ9LX7_7FQ_J_hLb zvCkvF1MCrYrRO8StZ`9si{vuK?aI1G{kyr;ib%lkDd&hkK(5PNvvvRw2e}7L6Lj1` z?(x7Jz`54345oLgs<3e~%2UY#HK+xZoL&TILU<;W1_-h9ny3yEZsmuX$uL06PbB^z zUM@fNsgd&PRWp~b0{-plOLIIBZc-1c zL-VUWk>Z@zvKf^?SfDm(mTFEA%u^I|z#idXERA6)6>5)?t&lHxW1ay)pT+V~CtZtP zbhl8NThEBEB4(-o3gI`(V_2N(p+0d*vh0kYTbPn8o#iNou1rekJ3;3vkqVq-5H=$f zG>wp4;h25S*HIepkLSJ`M+PH8|%-db6%vWx9#w! zop{9=Y<92uwdoW&I8%uZ(g(1}M82B7K}8RrrtCL{GwVE?9WttEIZ#Wha=mhFP=oAp zb+x0cu2Qa6hJqv935FF$DKQ#2Hear(Q}jlY`-|}c!yI;3hITWlMI><&Rya{ZLiK2% p_gEAn4|Ze|Cc(BL9avQBusUnx`UY!kVV*s^Fv+&A$AtYB{sD@C(MkXS delta 1108 zcmZ8fZEO>D9DZ)xwOxC?vaWUOR^XW9#Sa_m#taf;G$>;kOM|=wKCqnYVJls)Ub{)d zhk}@Z!lKK`U@r+8mnA~NTaC#8BMAxykeF;}B+*3qfQ!b7f)JCb&t1)e=5qh%{=b*! z`Td^U-u6G&z8xx@huHT9F#iU`kq>|cZirv?0hlUbP%B~NDx}usKx78)?FnGs7YHw% z56s<+=D$Qh{sb$&Z2|&+moV6mr(U&y%62@{Lv*b|TgyQpT8;L>7pZd$TYe_rC@-C-K-@0;>na6SbRxieJTZ^>+Yqqj+!lCLqj6iyFS;+9T2vZSS-H zVd?2aJy3Q=(jR?}s$WY7e4~JWOgg&%0#MU0eKa}=NCgKAsJSRz-#CZ+jk~tjoTo2O zx(u0(9@%BA+5mW~+(NZINTb`k=nw^Vx?eIw^yifOLi1hLb+|9z+QT*XdW7At19JvE zyC&U$Dtg8y=p#_>f8`p58_UB(-ve%=eBa1=)-{xW+Iq(NMyM++yyczx;}J@~=Dk1A zOpCAh#MUHRW_-&hc$Z{(^-_*9Z>^l&bdz4i12aHelo*RD*VMhI$O8N|9Ra6 zP}@!Xo!%VxUmj+k{|6${YuBU`yzr?M_%A%@ydML<7zUi zCeyuIDj8p?W>UJA)k`T=OB=a_ZZ`hk0D-?KwxF1=yem8;(uCNofYw?k_2-SAF9$Q7eiLqc(G Core - + Encrypted profile Profilo criptato - + Your tox profile seems to be encrypted, qTox can't open it Do you want to erase this profile ? Il tuo profilo Tox sembra essere criptato, qTox non può aprirlo\nVuoi eliminare questo profilo? @@ -245,18 +245,6 @@ Do you want to erase this profile ? General Settings Impostazioni Generali - - - Bad port - title of bad port popup - Numero porta errato - - - - The port you entered is invalid; please enter another. - text of bad port popup - Il numero della porta che hai inserito è invalido; per favore inseriscine un altro. - GeneralSettings @@ -271,68 +259,73 @@ Do you want to erase this profile ? Impostazioni Generali - + + Connection Settings + Impostazioni Connessione + + + Enable IPv6 (recommended) Text on a checkbox to enable IPv6 Abilita IPv6 (consigliato) - + Use translations Text on a checkbox to enable translations Abilita traduzioni - + Save settings to the working directory instead of the usual conf dir describes makeToxPortable checkbox Slava le impostazioni nella directory di lavoro corrente, invece della directory di default - + Make Tox portable Rendi qTox portabile - + Theme - Impostazioni tema + Impostazioni Tema - + Smiley Pack Text on smiley pack label Emoticons - - Proxy settings - Impostazioni proxy + + Use proxy (SOCKS5) + Usa proxy (SOCKS5) - + + Address + Text on proxy addr label + IP + + + + Port + Text on proxy port label + Porta + + + Disable UDP (not recommended) Text on checkbox to disable UDP Disabilita connessioni UDP (non raccomandato) - + This allows, e.g., toxing over Tor. It adds load to the Tox network however, so use only when necessary. force tcp checkbox tooltip Questo permette di usare qTox con Tor; tuttavia aggiunge carico alla rete Tox, quindi usalo solo se necessario. - - - Proxy address - Text on proxy addr label - IP - - - - Proxy port - Text on proxy port label - Porta - GenericChatForm From 32c56cbba4b99711147a8c7f890b23d3ad0b487e Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Tue, 7 Oct 2014 21:21:13 +0200 Subject: [PATCH 198/205] Update french translation --- translations/fr.qm | Bin 7085 -> 9699 bytes translations/fr.ts | 369 +++++++++++++++++++++++++++++++++++---------- 2 files changed, 286 insertions(+), 83 deletions(-) diff --git a/translations/fr.qm b/translations/fr.qm index 278415266881501d4faa330eddeeb5386c01c6cc..ff6462596e1d9c32e0ce42cdd9ba341507bc3a91 100644 GIT binary patch delta 3891 zcmai0e{37|6@O0bBz7FfNs}gNLivW4CY{o>TN5foe=JH;nih?a#9?d_?CQJ3N9;TI zd`@CC&HKevN~>)gj6#d(L_uPVwI~}y8)%iXbtpq`qB)Isq%d5yF}&Z zs=j%#lIU7b)l(O?6aM*Y4!sJ48~lxrzDZP>@*h4q2EDKPf4lEjM4?&#>rX!ktxx@b zo%;>&&iVgdgM)?6`#-hdNP95w!2F+y8lMU*ey|x1W&&4!l=Lr36p~a5h;oQ`6ZF@ssTGh?1FvU%WrnE>3WsPcx7EnOYLtdP8&Ei`63&Ed8h{KMkZz>qQSPBF zkn>m8Okqt*$8<^njU9+mw$$4_g)`rIhncp7ZO-P8jHGFa6eQxHCbWD&y2PO|=tLEx z!xm;zGlXsj227DL(_%(3Y}VH-C8Y^Frl$&6dpLkT8Nsd5glEkUKSu+3~&vQVg;&Us>2N*Z8Oh%4m6fu<4EP$@*Hw{CJW^LUx zL>`SDT-CyE8lXiurR0#NbMcHoK8(0_!V23G()}o&6ZlggQL%4x!Rj>wdP+GM*Fp)$BWGYw!Bvs!m;{N>=JSt>L}l5@8~IVDCzy3}_V&#r0sR)xaH>N z*DW)b*<5O@sh|Q_!WF=^WKlPs`XS>A;(YM`Hf6aOm>4=f^EU1U{DI%yzJPAPJjAzj z4s2Eysas6$PS+9Ea!ZiEF^XHLT)Nz4bcw?Sn3DJgEoP;8Cc4`kH0mw{J2u8;qr~Ip zOsY$0-ILv2T$E^@!kpGDF=krbV#pSXs-{HTR8%fFJEq~otS~ft#p$;tcCOjsoNB0Z;tfBnZCloAb?4tLO~W;^ zRbj9gwr*$m9KoU7OQEG)r9i@Y<$UQoR~pvWl}a}>j;td6cH^d1q#spmYAQjH^|9M| zx3T$aGGI|jho}rBcWSpQn_#C7>R3fVY?UYElnxDu&S+eZPH~>2W-=qASz>CgYweM; z$Y(XfX=%XCpN=9~Eb6e~VN0J@qM2ngx;iJ6)QrlSGvHXgo}|o1IJjvH7<7U14{#@QP!KDP$o5j!m~|` zJAINlRqV_8+-&CV?sg%A$GJO}^W&L&29IC2&bcY^0N|Lo$FO7vaqk2?oVhnd@il*Q z63C2;$dP5onG^|VaeSF93U*oa7A$a&$tqYTa!TAYnNhsa4L-LxA-k#DX*e-UeI^2O zMRA`I6AG?3vWui_#j??D&`gwM5}Z@yfSl3eabas#LN^o}pC<4u$Nk1=oD(VMd;&8X zA(Ty}IB+|iPyDT8#g`Vh_p;-BdcJ+(Y)kBj7;;8}?DBFU!SffemB20XLc?Kn&&?+; zVL}1AWeM8SxNmZ!m5E=GZBNx|+0LbAS+cWN%{J$Y2T~MiVAnWnyq!syKo;HM#?s;GQ|RmzsqD*=Y8hzN(*El<7`vJtL9I_!3{HFoa6@ayJMg zW^_Boe6Vs|KYt7FF5DDx*AZ6QxJe}A8s7{Prm9b5+&y`1p%^OeLz08bSacYrSXS=& EALos~qyPW_ delta 1427 zcmZ`%ZERCz6n@(K-h2CTd-u_g6;`qfvQgKk%A2O3k%$Af8g9Ob)S*Gz1+x{uR{lF>FAIvBu7*D&cvB+|BbMAZI z^E~G{&$){&pY1+n%Qgf2b3oNJ*jsM^&PlM*35vgfZ{7t|4npiY3^;00{|^I9eQ5Y` zCt$e%Pme~}XVHADf$oQ~_tEzOTO0>(60Yo9jNF~0^G6tao(E(}&pcmJ-JHJcg)m^R z(W~yOK-T#X=UC1GnBu(Ecc{TUH#^t|=%%^()3*TQ0_z>kP`-%`c`uSsCmZU24=7() zi4~XFa08ty1$Oow9X0%&O;#Tufj)L|>oUL%u)jtYiSJ3icH2)t#fg>Z?B#dw{TNx4 z{mDOZcqN&S!|f@!0D z_&Ok*HujGO>EcD><>m{3RBl|D7$@RE<2B1NojXk5obwXVNz>mS)RXmd=3Q4QvRbL> zL27KDkhDoMDrmdi7b5zc3s*+Q0EzoSUb;+AE0BtSs(tFmkR z7TQr*b`3?yI#J#^)y+OYL%CV3HbrFYj{^f$?2=>d-mbrC(lhUm>FQvJaQ? z5mB zddRc4eh?*Zr@T}07 zwdpmt@=SvVNqS;5e2R=vkuK`wJ;`LOHxHNB*3cLY#S)!`rVj0fz9wt-^hBbG?QPMB znpm$=hKH<<6ML+LUwA4M538~DVNFyX&qHWCv7#(-b>Vqj)%}!}!>e^vS7i-r_O91~ z!H2FQuin?SUZIT)j*<`sei9SKQ7l0%0!4p1dNdTi*QsF9Di>KBqzxU1qS%PUM~1Kd jZRjr2RHX9z`uP=2S#$e7ap9)OtZ8kS diff --git a/translations/fr.ts b/translations/fr.ts index 2057d56da..c43857b12 100644 --- a/translations/fr.ts +++ b/translations/fr.ts @@ -2,24 +2,58 @@ - AVPage + AVForm - - Video Settings - Options vidéo + + Audio/Video settings + - - - Show video preview - On a button - Montrer l'aperçu vidéo - - - + Hide video preview On a button - Cacher l'aperçu vidéo + Cacher l'aperçu vidéo + + + + Show video preview + On a button + Montrer l'aperçu vidéo + + + + AVPage + + Video Settings + Options vidéo + + + Show video preview + On a button + Montrer l'aperçu vidéo + + + Hide video preview + On a button + Cacher l'aperçu vidéo + + + + AVSettings + + + Form + + + + + Video settings + + + + + Show video preview + Montrer l'aperçu vidéo @@ -116,7 +150,7 @@ ChatForm - + Send a file Envoyer un fichier @@ -132,22 +166,36 @@ Copier + + Core + + + Encrypted profile + + + + + Your tox profile seems to be encrypted, qTox can't open it +Do you want to erase this profile ? + + + FileTransferInstance - + Save a file Title of the file saving dialog Sauvegarder un fichier - + Location not writable Title of permissions popup Impossible d'écrire ici - + You do not have permission to write that location. Choose another, or cancel the save dialog. text of permissions popup Vous n'avez pas la permission d'écrire ici. Choisissez un audre endroit, ou annulez. @@ -219,71 +267,153 @@ FriendWidget - + Copy friend ID Menu to copy the Tox ID of that friend Copier l'ID ami - + Invite in group Menu to invite a friend in a groupchat Inviter dans un groupe - + Remove friend Menu to remove the friend from our friendlist Supprimer ami + + GeneralForm + + + General Settings + Options Générales + + GeneralPage - General Settings - Options Générales + Options Générales - Enable IPv6 (recommended) Text on a checkbox to enable IPv6 - Activer IPv6 (recommandé) + Activer IPv6 (recommandé) - Use translations Text on a checkbox to enable translations - Utiliser les traductions + Utiliser les traductions - Make Tox portable Text on a checkbox to make qTox a portable application - Rendre Tox portable + Rendre Tox portable - Save settings to the working directory instead of the usual conf dir describes makeToxPortable checkbox - Sauvegarde les options dans le dossier courant au lieu du dossier de configuration habituel + Sauvegarde les options dans le dossier courant au lieu du dossier de configuration habituel - Theme - Thème + Thème - Smiley Pack - Pack de smileys + Pack de smileys + + + + GeneralSettings + + + Form + + + + + General Settings + Options Générales + + + + Use translations + Text on a checkbox to enable translations + Utiliser les traductions + + + + Save settings to the working directory instead of the usual conf dir + describes makeToxPortable checkbox + Sauvegarde les options dans le dossier courant au lieu du dossier de configuration habituel + + + + Make Tox portable + Rendre Tox portable + + + + Theme + Thème + + + + Smiley Pack + Text on smiley pack label + Pack de smileys + + + + Connection Settings + + + + + Enable IPv6 (recommended) + Text on a checkbox to enable IPv6 + Activer IPv6 (recommandé) + + + + This allows, e.g., toxing over Tor. It adds load to the Tox network however, so use only when necessary. + force tcp checkbox tooltip + + + + + Disable UDP (not recommended) + Text on checkbox to disable UDP + + + + + Use proxy (SOCKS5) + + + + + Address + Text on proxy addr label + + + + + Port + Text on proxy port label + GenericChatForm - - + + Save chat log Sauvegarder l'historique de conversation @@ -291,18 +421,17 @@ GroupChatForm - + %1 users in chat Number of users in chat %1 personnes - <Unknown> - <Inconnu> + <Inconnu> - + %1 users in chat %1 personnes @@ -314,52 +443,88 @@ GroupWidget - - + + %1 users in chat %1 personnes - - + + 0 users in chat 0 personnes - + Quit group Menu to quit a groupchat Quitter le groupe + + IdentityForm + + + Your identity + + + IdentityPage - Public Information - Informations Publiques + Informations Publiques - Name Username/nick - Nom + Nom - Status Status message - Status + Status - Tox ID - ID Tox + ID Tox - Your Tox ID - Votre ID Tox + Votre ID Tox + + + + IdentitySettings + + + Form + + + + + Public Information + Informations Publiques + + + + Name + Nom + + + + Status + Status + + + + Tox ID + ID Tox + + + + Your Tox ID (click to copy) + @@ -370,46 +535,54 @@ qTox - + Your name Votre nom - + Your status Votre status - + Add friends Ajouter des amis - + Create a group chat Creer un groupe - + View completed file transfers Voir les transfers de fichiers terminés - + Change your settings Changer les options - + Close Fermer - + Ctrl+Q Ctrl+Q + + PrivacyForm + + + Privacy settings + + + SelfCamView @@ -422,44 +595,36 @@ SettingsDialog - qTox – Settings - qTox — Options + qTox — Options - General - General + General - Identity - Identité + Identité - Privacy - Vie Privée + Vie Privée - Audio/Video - Audio/Vidéo + Audio/Vidéo - Ok - Ok + Ok - Cancel - Annuler + Annuler - Apply - Appliquer + Appliquer @@ -513,25 +678,63 @@ Ctrl+Q - + Online Button to set your status to 'Online' Connecté - + Away Button to set your status to 'Away' Indisponnible - + Busy Button to set your status to 'Busy' Occupé - + + Choose a profile picture + + + + + + + Error + + + + + Unable to open this file + + + + + Unable to read this image + + + + + This image is too big + + + + + Toxcore failed to start, the application will terminate after you close this message. + + + + + toxcore failed to start with your proxy settings. qTox cannot run; please modify your settings and restart. + popup text + + + + <Unknown> Placeholder when we don't know someone's name in a group chat <Inconnu> From b7dcbdc4742b8ecdafb638674ba19af1c92208ee Mon Sep 17 00:00:00 2001 From: Zetok Zalbavar Date: Tue, 7 Oct 2014 20:33:06 +0100 Subject: [PATCH 199/205] Update Polish translation --- translations/pl.qm | Bin 6709 -> 9279 bytes translations/pl.ts | 373 +++++++++++++++++++++++++++++++++++---------- 2 files changed, 289 insertions(+), 84 deletions(-) diff --git a/translations/pl.qm b/translations/pl.qm index d05682dd157ed6c4cdf4f6a3a40d7171139dab1b..b9b482a495036fd5d27703a3aa12a704ffe9a1fc 100644 GIT binary patch literal 9279 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 HYhLspDiHb{ delta 1380 zcmZ`$ZA@Eb7(KUrZ*RZuEzr_J+hK!)Y1FX~=0;+Il}=hr24QT=x}>wxD=Te!ffk{E ztVXwBreX1-BZIg^w-_|;BSkkA!xCpC{LttS|M(GSjDKd#9Lewl^{I>|m)IuF)1LP^ z=RD7OW`plGo^a%L0sJAr*#`E~3xKNyY;ua~F!ms#rM`&H*4s_^C7rzK z8jy2d)H|2*ppQP}`GX7;{rt(J0B6*H_3|yi*vYb!8LD5f@z4wjyw1i)#sHghwU#xq zQ%&^0Y>d4<%8~FfcHVOku-s-d8riP#W^ypxXX}mUm@e02E|G| z17}bI`>5sxu8Q7m!-Bc)Bqec4IPvN4lyF*@|M@vevfs!(`#cSHpGoZhEJp?rQ{|~2 z=nN^-$Yd7{GGn?L`~WatHZ4w_CBbIX_u>+5WH5g+9U>voy!>h-MSsPz;~G`{Zfom3 zWbD{!O&_35jjvgM-Si$RPvri?$l+=0rJQ-b=_IgRcxIwz`X-I|7N+&t2TSsYH5{I@<23Mcv7?WN43D`_Q$k9 z*s-Vu9Ylxqg6pQQRP-2uRf=S-5${zipi-=Jd^!z zm}Ble>yV$^_3IF?r@mdo;tKma(S;%0LN9#uOTjSJ5CTSef`Pu4gUaB5uS*&Bg#v|S zGzw~jZOfaydvt2PrY%>7Frr8!Lo#U$qPHl*`}_Km*#cc!OF0maCY7E$BlxL1hB)yW zaDZwIGL$0Q;vbB~m4^NCn5>l2u)?1}ie!=+V?#?c)h#DWvs$@FX!#+c%0)ln&Y4TG zD$u2Fa98JyYbPkx$k2{NQC8QUDAnjd2L_O(Iii$a3JQ0K6N*HkV<7%iw0nJi?qYzo z=wG{?&rbK-r;ge^b>;nqt6hIa^{r+8KlbW!%~`eHcdu=Pj$`Jye;hita=+RBFO61T A*#H0l diff --git a/translations/pl.ts b/translations/pl.ts index 481762e0e..a91d8a8a4 100644 --- a/translations/pl.ts +++ b/translations/pl.ts @@ -1,25 +1,59 @@ - + - AVPage + AVForm - - Video Settings - Ustawienia wideo + + Audio/Video settings + Ustawienia audio/video - - + + Hide video preview + On a button + Ukryj podgląd wideo + + + Show video preview On a button Pokaż podgląd wideo + + + AVPage + + Video Settings + Ustawienia wideo + + + Show video preview + On a button + Pokaż podgląd wideo + - Hide video preview On a button - Ukryj podgląd wideo + Ukryj podgląd wideo + + + + AVSettings + + + Form + + + + + Video settings + Ustawienia wideo + + + + Show video preview + Pokaż podgląd wideo @@ -105,27 +139,42 @@ ChatForm - + Send a file Wyślij plik + + Core + + + Encrypted profile + Zaszyfrowany profil + + + + Your tox profile seems to be encrypted, qTox can't open it +Do you want to erase this profile ? + Twój profil zdaje się być zaszyfrowany, qTox nie jest w stanie go otworzyć +Czy chcesz usunąć ten profil ? + + FileTransferInstance - + Save a file Title of the file saving dialog Zapisz plik - + Location not writable Title of permissions popup Nie można zapisać w lokacji - + You do not have permission to write that location. Choose another, or cancel the save dialog. text of permissions popup Nie masz uprawnienia by zapisać w tej lokacji. Wybierz inną lub anuluj zapis. @@ -191,72 +240,155 @@ FriendWidget - + Copy friend ID Menu to copy the Tox ID of that friend Kopiuj ID znajomej/go - + Invite in group Menu to invite a friend in a groupchat Zaproś do grupy - + Remove friend Menu to remove the friend from our friendlist Usuń znajomego + + GeneralForm + + + General Settings + Główne ustawienia + + GeneralPage - + General Settings + Główne ustawienia + + + Enable IPv6 (recommended) + Text on a checkbox to enable IPv6 + Użyj IPv6 (rekomendowane) + + + Use translations + Text on a checkbox to enable translations + Użyj tłumaczenia + + + Make Tox portable + Text on a checkbox to make qTox a portable application + Zrób Tox przenośnym + + + Save settings to the working directory instead of the usual conf dir + describes makeToxPortable checkbox + Zamiast domyślnego katalogu użyj obecnego do zapisania ustawień + + + Theme + Motyw + + + Smiley Pack + needs better translation + Paczka uśmiechów + + + + GeneralSettings + + + Form + + + + General Settings Główne ustawienia - - Enable IPv6 (recommended) - Text on a checkbox to enable IPv6 - Użyj IPv6 (rekomendowane) - - - + Use translations - Text on a checkbox to enable translations + Text on a checkbox to enable translations Użyj tłumaczenia - - Make Tox portable - Text on a checkbox to make qTox a portable application - Zrób Tox przenośnym - - - + Save settings to the working directory instead of the usual conf dir - describes makeToxPortable checkbox + describes makeToxPortable checkbox Zamiast domyślnego katalogu użyj obecnego do zapisania ustawień - + + Make Tox portable + Zrób Tox przenośnym + + + Theme Motyw - + Smiley Pack - needs better translation + Text on smiley pack label + better translation? anyone? Paczka uśmiechów + + + Connection Settings + Ustawienia połączenia + + + + Enable IPv6 (recommended) + Text on a checkbox to enable IPv6 + Użyj IPv6 (rekomendowane) + + + + This allows, e.g., toxing over Tor. It adds load to the Tox network however, so use only when necessary. + force tcp checkbox tooltip + To pozwala n.p. na toxowanie przez Tora. Niestety obciąża to sieć Tox, więc używaj tylko w razie potrzeby. + + + + Disable UDP (not recommended) + Text on checkbox to disable UDP + Wyłącz UDP (nie rekomendowane) + + + + Use proxy (SOCKS5) + Użyj proxy (SOCKS5) + + + + Address + Text on proxy addr label + Adres + + + + Port + Text on proxy port label + Port + GenericChatForm - - + + Save chat log Zapisz historię rozmowy @@ -264,18 +396,17 @@ GroupChatForm - + %1 users in chat Number of users in chat %1 użytkowników w czacie - <Unknown> - <Nieznany/a> + <Nieznany/a> - + %1 users in chat %1 użytkowników w czacie @@ -283,52 +414,88 @@ GroupWidget - - + + %1 users in chat %1 użytkowników w czacie - - + + 0 users in chat 0 użytkowników w czacie - + Quit group Menu to quit a groupchat Opuść grupę + + IdentityForm + + + Your identity + Twoja tożsamość + + IdentityPage - + Public Information + Informacja publiczna + + + Name + Username/nick + Nick + + + Status + Status message + Status + + + Tox ID + Tox ID + + + Your Tox ID + Twój Tox ID + + + + IdentitySettings + + + Form + + + + Public Information Informacja publiczna - + Name - Username/nick Nick - + Status - Status message Status - + Tox ID Tox ID - - Your Tox ID - Twój Tox ID + + Your Tox ID (click to copy) + Twój Tox ID (kliknij by skopiować) @@ -339,47 +506,55 @@ qTox - + Your name Twój nick - + Your status Twój status - + Add friends Dodaj znajomych - + Create a group chat Utwórz czat grupowy - + View completed file transfers Zobacz zakończone transfery plików - + Change your settings translated as "change settings"; seems to be simpler this way Zmień ustawienia - + Close Zamknij - + Ctrl+Q Ctrl+Q + + PrivacyForm + + + Privacy settings + Ustawienia prywatności + + SelfCamView @@ -392,68 +567,98 @@ SettingsDialog - qTox – Settings - qTox – Ustawienia + qTox – Ustawienia - General - Główne + Główne - Identity - Tożsamość + Tożsamość - Privacy - Prywatność + Prywatność - Audio/Video - Audio/Wideo + Audio/Wideo - Ok - Ok + Ok - Cancel - Anuluj + Anuluj - Apply - Zastosuj + Zastosuj Widget - + Online Button to set your status to 'Online' Online - + Away Button to set your status to 'Away' Nieobecny/a - + Busy Button to set your status to 'Busy' Zajęty/a - + + Choose a profile picture + Wybierz obrazek profilu + + + + + + Error + Błąd + + + + Unable to open this file + Nie można otworzyć tego pliku + + + + Unable to read this image + Nie można odczytać tego obrazka + + + + This image is too big + Ten obrazek jest zbyt wielki + + + + Toxcore failed to start, the application will terminate after you close this message. + Nie udało się uruchomić Toxcore, aplikacja zamknie się po zamknięciu tej wiadomości. + + + + toxcore failed to start with your proxy settings. qTox cannot run; please modify your settings and restart. + popup text + Nie udało się uruchomić toxcore z twoimi ustawieniami proxy. qTox nie może działać, proszę zmodyfikuj ustawienia i zrestartuj. + + + <Unknown> Placeholder when we don't know someone's name in a group chat <Nieznany/a> From afc77f63dbd650383e8baad7716c79842f1b278e Mon Sep 17 00:00:00 2001 From: agilob Date: Tue, 7 Oct 2014 11:50:36 +0200 Subject: [PATCH 200/205] css styles for mainHead and mainContent in widget.cpp fixes problems with ugly UI on non-standard system theme. before: https://i.imgur.com/XJ0mbpi.png after: https://imgur.com/a/UbgNz --- res.qrc | 2 ++ ui/settings/mainContent.css | 36 ++++++++++++++++++++++++++++++++++++ ui/settings/mainHead.css | 5 +++++ widget/widget.cpp | 2 ++ 4 files changed, 45 insertions(+) create mode 100644 ui/settings/mainContent.css create mode 100644 ui/settings/mainHead.css diff --git a/res.qrc b/res.qrc index e8156ac58..4ef12f901 100644 --- a/res.qrc +++ b/res.qrc @@ -136,5 +136,7 @@ ui/chatroomWidgets/genericChatroomWidget.css ui/fileTransferInstance/sliverRTEdge.png ui/window/statusPanel.css + ui/settings/mainContent.css + ui/settings/mainHead.css diff --git a/ui/settings/mainContent.css b/ui/settings/mainContent.css new file mode 100644 index 000000000..e08dc24b5 --- /dev/null +++ b/ui/settings/mainContent.css @@ -0,0 +1,36 @@ +QCheckBox +{ + color: black; +} + +QLabel +{ + color: black; +} + +QGroupBox::title +{ + color: black; + background-color: white; +} + +QWidget +{ + color: black; + background-color: white; +} + +QComboBox +{ + background-color: white; +} + +QComboBox:on QComboBox:off QComboBox:drop-down +{ + background: rgba(18, 18, 18, 204); +} + +QComboBox:active +{ + background: white; +} diff --git a/ui/settings/mainHead.css b/ui/settings/mainHead.css new file mode 100644 index 000000000..3a97d7d35 --- /dev/null +++ b/ui/settings/mainHead.css @@ -0,0 +1,5 @@ +QWidget +{ + color: black; + background: white; +} diff --git a/widget/widget.cpp b/widget/widget.cpp index 53a34449c..dfa25fffe 100644 --- a/widget/widget.cpp +++ b/widget/widget.cpp @@ -74,6 +74,8 @@ Widget::Widget(QWidget *parent) ui->mainHead->setLayout(new QVBoxLayout()); ui->mainHead->layout()->setMargin(0); ui->mainHead->layout()->setSpacing(0); + ui->mainHead->setStyleSheet(Style::getStylesheet(":ui/settings/mainHead.css")); + ui->mainContent->setStyleSheet(Style::getStylesheet(":ui/settings/mainContent.css")); contactListWidget = new FriendListWidget(); ui->friendList->setWidget(contactListWidget); From aa11caa63b105b0eff56ed695ab314321bbe2777 Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Tue, 7 Oct 2014 23:05:05 +0200 Subject: [PATCH 201/205] debian: Exclude libs from source package --- debian/source/options | 1 + 1 file changed, 1 insertion(+) create mode 100644 debian/source/options diff --git a/debian/source/options b/debian/source/options new file mode 100644 index 000000000..2c6d70e0d --- /dev/null +++ b/debian/source/options @@ -0,0 +1 @@ +--diff-ignore=libs From f441ffd74a5872e203f2d810d62af3b0a5da2e31 Mon Sep 17 00:00:00 2001 From: "Tux3 / Mlkj / !Lev.uXFMLA" Date: Wed, 8 Oct 2014 00:41:56 +0200 Subject: [PATCH 202/205] Try to link opencv statically in linux packages --- qtox.pro | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/qtox.pro b/qtox.pro index 879112e5f..3b95cdf1f 100644 --- a/qtox.pro +++ b/qtox.pro @@ -62,7 +62,10 @@ win32 { contains(STATICPKG, YES) { target.path = /usr/bin INSTALLS += target - LIBS += -L$$PWD/libs/lib/ -Wl,-Bstatic -ltoxcore -ltoxav -lsodium -Wl,-Bdynamic -lopus -lvpx -lopenal -lopencv_core -lopencv_highgui + LIBS += -L$$PWD/libs/lib/ -lopus -lvpx -lopenal -Wl,-Bstatic -ltoxcore -ltoxav -lsodium -lopencv_highgui -lopencv_imgproc -lopencv_core -lz -Wl,-Bdynamic + LIBS += -Wl,-Bstatic -ljpeg -ltiff -lpng -ljasper -lIlmImf -lIlmThread -lIex -ldc1394 -lraw1394 -lHalf -lz -llzma -ljbig + LIBS += -Wl,-Bdynamic -ltbb -lv4l1 -lv4l2 -lgnutls -lrtmp -lgnutls -lavformat -lavcodec -lavutil -lavfilter -lswscale -lusb-1.0 + } else { LIBS += -L$$PWD/libs/lib/ -ltoxcore -ltoxav -lvpx -lopenal -lopencv_core -lopencv_highgui } From 54eb425238a277a8f23c599041eec281f3b43a5a Mon Sep 17 00:00:00 2001 From: dubslow Date: Tue, 7 Oct 2014 21:20:38 -0500 Subject: [PATCH 203/205] add ringtone (not well done, but still better than status quo) --- audio/ToxicIncomingCall.pcm | Bin 0 -> 300000 bytes res.qrc | 1 + widget/widget.cpp | 21 +++++++++++++++++++++ widget/widget.h | 1 + 4 files changed, 23 insertions(+) create mode 100644 audio/ToxicIncomingCall.pcm diff --git a/audio/ToxicIncomingCall.pcm b/audio/ToxicIncomingCall.pcm new file mode 100644 index 0000000000000000000000000000000000000000..8239c74cf46aac69a711873f68a1b8a3b71b611f GIT binary patch literal 300000 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