From 36adfc89e995e86f463396b7ef7a7616204fc18e Mon Sep 17 00:00:00 2001 From: Diadlo Date: Sat, 7 Oct 2017 20:02:03 +0300 Subject: [PATCH] refactor(profileform): Integrate ProfileInfo in ProfileForm --- src/widget/form/profileform.cpp | 318 ++++++++++++++++---------------- src/widget/form/profileform.h | 9 +- src/widget/widget.cpp | 8 +- src/widget/widget.h | 42 +++-- 4 files changed, 192 insertions(+), 185 deletions(-) diff --git a/src/widget/form/profileform.cpp b/src/widget/form/profileform.cpp index f5d62c7e0..65f40577d 100644 --- a/src/widget/form/profileform.cpp +++ b/src/widget/form/profileform.cpp @@ -20,6 +20,7 @@ #include "profileform.h" #include "ui_profileform.h" #include "src/core/core.h" +#include "src/model/profile/iprofileinfo.h" #include "src/net/toxme.h" #include "src/nexus.h" #include "src/persistence/profile.h" @@ -43,22 +44,73 @@ #include #include #include +#include #include #include #include #include -ProfileForm::ProfileForm(QWidget* parent) +static const QMap SET_AVATAR_ERROR = { + { IProfileInfo::SetAvatarResult::CanNotOpen, + ProfileForm::tr("Unable to open this file.") }, + { IProfileInfo::SetAvatarResult::CanNotRead, + ProfileForm::tr("Unable to read this image.") }, + { IProfileInfo::SetAvatarResult::TooLarge, + ProfileForm::tr("The supplied image is too large.\nPlease use another image.") }, + { IProfileInfo::SetAvatarResult::EmptyPath, + ProfileForm::tr("Empty path is unavaliable") }, +}; + +static const QMap> RENAME_ERROR = { + { IProfileInfo::RenameResult::Error, + { ProfileForm::tr("Failed to rename"), + ProfileForm::tr("Couldn't rename the profile to \"%1\"") } + } , + { IProfileInfo::RenameResult::ProfileAlreadyExists, + { ProfileForm::tr("Profile already exists"), + ProfileForm::tr("A profile named \"%1\" already exists.") } + }, + { IProfileInfo::RenameResult::EmptyName, + { ProfileForm::tr("Empty name"), + ProfileForm::tr("Empty name is unavaliable") } + }, +}; + +static const QMap> SAVE_ERROR = { + { IProfileInfo::SaveResult::NoWritePermission, + { ProfileForm::tr("Location not writable", "Title of permissions popup"), + ProfileForm::tr("You do not have permission to write that location. Choose " + "another, or cancel the save dialog.", "text of permissions popup") }, + }, + { IProfileInfo::SaveResult::Error, + { ProfileForm::tr("Failed to copy file"), + ProfileForm::tr("The file you chose could not be written to.") } + }, + { IProfileInfo::SaveResult::EmptyPath, + { ProfileForm::tr("Empty path"), + ProfileForm::tr("Empty path is unavaliable") } + }, +}; + +static const QPair CAN_NOT_CHANGE_PASSWORD = { + ProfileForm::tr("Couldn't change password"), + ProfileForm::tr("Couldn't change password on the database, " + "it might be corrupted or use the old password.") +}; + +ProfileForm::ProfileForm(IProfileInfo* profileInfo, QWidget* parent) : QWidget{parent} , qr{nullptr} + , profileInfo{profileInfo} { bodyUI = new Ui::IdentitySettings; bodyUI->setupUi(this); core = Core::getInstance(); - bodyUI->userNameLabel->setToolTip( - tr("Tox user names cannot exceed %1 characters.").arg(tox_max_name_length())); - bodyUI->userName->setMaxLength(tox_max_name_length()); + const uint32_t maxNameLength = tox_max_name_length(); + const QString toolTip = tr("Tox user names cannot exceed %1 characters.").arg(maxNameLength); + bodyUI->userNameLabel->setToolTip(toolTip); + bodyUI->userName->setMaxLength(static_cast(maxNameLength)); // tox toxId = new ClickableTE(); @@ -72,8 +124,8 @@ ProfileForm::ProfileForm(QWidget* parent) /* Toxme section init */ bodyUI->toxmeServersList->addItem("toxme.io"); QString toxmeInfo = Settings::getInstance().getToxmeInfo(); - if (toxmeInfo.isEmpty()) // User not registered - { + // User not registered + if (toxmeInfo.isEmpty()) { showRegisterToxme(); } else { showExistingToxme(); @@ -95,6 +147,7 @@ ProfileForm::ProfileForm(QWidget* parent) connect(profilePicture, &MaskablePixmapWidget::clicked, this, &ProfileForm::onAvatarClicked); connect(profilePicture, &MaskablePixmapWidget::customContextMenuRequested, this, &ProfileForm::showProfilePictureContextMenu); + QHBoxLayout* publicGrouplayout = qobject_cast(bodyUI->publicGroup->layout()); publicGrouplayout->insertWidget(0, profilePicture); publicGrouplayout->insertSpacing(1, 7); @@ -108,6 +161,7 @@ ProfileForm::ProfileForm(QWidget* parent) connect(bodyUI->toxIdLabel, &CroppingLabel::clicked, this, &ProfileForm::copyIdClicked); connect(toxId, &ClickableTE::clicked, this, &ProfileForm::copyIdClicked); + // TODO: Move to model connect(core, &Core::idSet, this, &ProfileForm::setToxId); connect(bodyUI->userName, &QLineEdit::editingFinished, this, &ProfileForm::onUserNameEdited); connect(bodyUI->statusMessage, &QLineEdit::editingFinished, @@ -131,6 +185,7 @@ ProfileForm::ProfileForm(QWidget* parent) connect(bodyUI->toxmeUpdateButton, &QPushButton::clicked, this, &ProfileForm::onRegisterButtonClicked); + // TODO: Move to model connect(core, &Core::usernameSet, this, [=](const QString& val) { bodyUI->userName->setText(val); }); connect(core, &Core::statusMessageSet, this, @@ -147,8 +202,8 @@ ProfileForm::ProfileForm(QWidget* parent) void ProfileForm::prFileLabelUpdate() { - Nexus& nexus = Nexus::getInstance(); - bodyUI->prFileLabel->setText(tr("Current profile: ") + nexus.getProfile()->getName() + ".tox"); + const QString name = profileInfo->getProfileName(); + bodyUI->prFileLabel->setText(tr("Current profile: ") + name + ".tox"); } ProfileForm::~ProfileForm() @@ -201,40 +256,37 @@ bool ProfileForm::eventFilter(QObject* object, QEvent* event) void ProfileForm::showProfilePictureContextMenu(const QPoint& point) { - QPoint pos = profilePicture->mapToGlobal(point); + const QPoint pos = profilePicture->mapToGlobal(point); QMenu contextMenu; - QAction* removeAction = - contextMenu.addAction(style()->standardIcon(QStyle::SP_DialogCancelButton), tr("Remove")); - QAction* selectedItem = contextMenu.exec(pos); + const QIcon icon = style()->standardIcon(QStyle::SP_DialogCancelButton); + const QAction* removeAction = contextMenu.addAction(icon, tr("Remove")); + const QAction* selectedItem = contextMenu.exec(pos); - if (selectedItem == removeAction) - Nexus::getProfile()->removeAvatar(); + if (selectedItem == removeAction) { + profileInfo->removeAvatar(); + } } void ProfileForm::copyIdClicked() { - QString txt = toxId->text(); - txt.remove(QRegularExpression("<[^>]*>")); - QApplication::clipboard()->setText(txt, QClipboard::Clipboard); - if (QApplication::clipboard()->supportsSelection()) - QApplication::clipboard()->setText(txt, QClipboard::Selection); - + profileInfo->copyId(); if (!hasCheck) { bodyUI->toxIdLabel->setText(bodyUI->toxIdLabel->text() + " ✔"); hasCheck = true; } + timer.start(); } void ProfileForm::onUserNameEdited() { - Core::getInstance()->setUsername(bodyUI->userName->text()); + profileInfo->setUsername(bodyUI->userName->text()); } void ProfileForm::onStatusMessageEdited() { - Core::getInstance()->setStatusMessage(bodyUI->statusMessage->text()); + profileInfo->setStatusMessage(bodyUI->statusMessage->text()); } void ProfileForm::onSelfAvatarLoaded(const QPixmap& pic) @@ -259,138 +311,89 @@ void ProfileForm::setToxId(const ToxId& id) void ProfileForm::onAvatarClicked() { - auto picToPng = [](QPixmap pic) { - QByteArray bytes; - QBuffer buffer(&bytes); - buffer.open(QIODevice::WriteOnly); - pic.save(&buffer, "PNG"); - buffer.close(); - return bytes; - }; + const QString filter = Nexus::getSupportedImageFilter(); + const QString path = QFileDialog::getOpenFileName(Q_NULLPTR, tr("Choose a profile picture"), + QDir::homePath(), filter, nullptr); - QString path = QFileDialog::getOpenFileName(Q_NULLPTR, tr("Choose a profile picture"), - QDir::homePath(), Nexus::getSupportedImageFilter(), 0); - if (path.isEmpty()) - return; - - QFile file(path); - file.open(QIODevice::ReadOnly); - if (!file.isOpen()) { - GUI::showError(tr("Error"), tr("Unable to open this file.")); + const IProfileInfo::SetAvatarResult result = profileInfo->setAvatar(path); + if (result == IProfileInfo::SetAvatarResult::OK) { return; } - QPixmap pic; - if (!pic.loadFromData(file.readAll())) { - GUI::showError(tr("Error"), tr("Unable to read this image.")); - return; - } - - // Limit the avatar size to 64kB - // We do a first rescale to 256x256 in case the image was huge, then keep tryng from here - QByteArray bytes{picToPng(pic)}; - if (bytes.size() > 65535) { - pic = pic.scaled(256, 256, Qt::KeepAspectRatio, Qt::SmoothTransformation); - bytes = picToPng(pic); - } - if (bytes.size() > 65535) - bytes = picToPng(pic.scaled(128, 128, Qt::KeepAspectRatio, Qt::SmoothTransformation)); - if (bytes.size() > 65535) - bytes = picToPng(pic.scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation)); - if (bytes.size() > 65535) - bytes = picToPng(pic.scaled(32, 32, Qt::KeepAspectRatio, Qt::SmoothTransformation)); - - // If this happens, you're really doing it on purpose. - if (bytes.size() > 65535) { - QMessageBox::critical(this, tr("Error"), - tr("The supplied image is too large.\nPlease use another image.")); - return; - } - - Nexus::getProfile()->setAvatar(bytes, core->getSelfPublicKey()); + GUI::showError(tr("Error"), SET_AVATAR_ERROR[result]); } void ProfileForm::onRenameClicked() { - Nexus& nexus = Nexus::getInstance(); - QString cur = nexus.getProfile()->getName(); - QString title = tr("Rename \"%1\"", "renaming a profile").arg(cur); - do { - QString name = QInputDialog::getText(this, title, title + ":"); - if (name.isEmpty()) - break; - name = Core::sanitize(name); + const QString cur = profileInfo->getProfileName(); + const QString title = tr("Rename \"%1\"", "renaming a profile").arg(cur); + const QString name = QInputDialog::getText(this, title, title + ":"); + if (name.isEmpty()) { + return; + } - if (Profile::exists(name)) - GUI::showError(tr("Profile already exists", "rename failure title"), - tr("A profile named \"%1\" already exists.", "rename confirm text").arg(name)); - else if (!nexus.getProfile()->rename(name)) - GUI::showError(tr("Failed to rename", "rename failed title"), - tr("Couldn't rename the profile to \"%1\"").arg(cur)); - else { - prFileLabelUpdate(); - break; - } - } while (true); + const IProfileInfo::RenameResult result = profileInfo->renameProfile(name); + if (result == IProfileInfo::RenameResult::OK) { + return; + } + + const QPair error = RENAME_ERROR[result]; + GUI::showError(error.first, error.second.arg(name)); + prFileLabelUpdate(); } void ProfileForm::onExportClicked() { - QString current = Nexus::getProfile()->getName() + Core::TOX_EXT; - QString path = QFileDialog::getSaveFileName(Q_NULLPTR, tr("Export profile", "save dialog title"), - QDir::home().filePath(current), - tr("Tox save file (*.tox)", "save dialog filter"), 0); - if (!path.isEmpty()) { - if (!Nexus::tryRemoveFile(path)) { - GUI::showWarning(tr("Location not writable", "Title of permissions popup"), - tr("You do not have permission to write that location. Choose " - "another, or cancel the save dialog.", - "text of permissions popup")); - return; - } - if (!QFile::copy(Settings::getInstance().getSettingsDirPath() + current, path)) - GUI::showWarning(tr("Failed to copy file"), - tr("The file you chose could not be written to.")); + const QString current = profileInfo->getProfileName() + Core::TOX_EXT; + //:save dialog title + const QString path = QFileDialog::getSaveFileName(Q_NULLPTR, tr("Export profile"), + QDir::home().filePath(current), + //: save dialog filter + tr("Tox save file (*.tox)"), nullptr); + const IProfileInfo::SaveResult result = profileInfo->exportProfile(path); + if (result == IProfileInfo::SaveResult::OK) { + return; } + + const QPair error = SAVE_ERROR[result]; + GUI::showWarning(error.first, error.second); } void ProfileForm::onDeleteClicked() { - if (GUI::askQuestion(tr("Really delete profile?", "deletion confirmation title"), - tr("Are you sure you want to delete this profile?", - "deletion confirmation text"))) { - Nexus& nexus = Nexus::getInstance(); - - QVector manualDeleteFiles = nexus.getProfile()->remove(); - - if (!manualDeleteFiles.empty()) { - QString message = - tr("The following files could not be deleted:", "deletion failed text part 1") + "\n\n"; - - for (auto& file : manualDeleteFiles) { - message = message + file + "\n"; - } - - message = - message + "\n" + tr("Please manually remove them.", "deletion failed text part 2"); - - GUI::showError(tr("Files could not be deleted!", "deletion failed title"), message); - } - - nexus.showLoginLater(); + const QString title = tr("Really delete profile?", "deletion confirmation title"); + const QString question = tr("Are you sure you want to delete this profile?", + "deletion confirmation text"); + if (!GUI::askQuestion(title, question)) { + return; } + + // TODO: Use QStringList + const QVector manualDeleteFiles = profileInfo->removeProfile(); + if (manualDeleteFiles.empty()) { + return; + } + + //: deletion failed text part 1 + QString message = tr("The following files could not be deleted:") + "\n\n"; + for (const QString& file : manualDeleteFiles) { + message += file + "\n"; + } + + //: deletion failed text part 2 + message += "\n" + tr("Please manually remove them."); + + GUI::showError(tr("Files could not be deleted!", "deletion failed title"), message); } void ProfileForm::onLogoutClicked() { - Nexus& nexus = Nexus::getInstance(); - Settings::getInstance().saveGlobal(); - nexus.showLoginLater(); + profileInfo->logout(); } void ProfileForm::setPasswordButtonsText() { - if (Nexus::getProfile()->isEncrypted()) { + if (profileInfo->isEncrypted()) { bodyUI->changePassButton->setText(tr("Change password", "button text")); bodyUI->deletePassButton->setVisible(true); } else { @@ -401,61 +404,55 @@ void ProfileForm::setPasswordButtonsText() void ProfileForm::onCopyQrClicked() { - QApplication::clipboard()->setImage(*qr->getImage()); + profileInfo->copyQr(*qr->getImage()); } void ProfileForm::onSaveQrClicked() { - QString current = Nexus::getProfile()->getName() + ".png"; - QString path = QFileDialog::getSaveFileName(Q_NULLPTR, tr("Save", "save qr image"), - QDir::home().filePath(current), - tr("Save QrCode (*.png)", "save dialog filter"), 0); - if (!path.isEmpty()) { - if (!Nexus::tryRemoveFile(path)) { - GUI::showWarning(tr("Location not writable", "Title of permissions popup"), - tr("You do not have permission to write that location. Choose " - "another, or cancel the save dialog.", - "text of permissions popup")); - return; - } - if (!qr->saveImage(path)) - GUI::showWarning(tr("Failed to copy file"), - tr("The file you chose could not be written to.")); + const QString current = profileInfo->getProfileName() + ".png"; + const QString path = QFileDialog::getSaveFileName( + Q_NULLPTR, tr("Save", "save qr image"), QDir::home().filePath(current), + tr("Save QrCode (*.png)", "save dialog filter"), nullptr); + + const IProfileInfo::SaveResult result = profileInfo->saveQr(*qr->getImage(), path); + if (result == IProfileInfo::SaveResult::OK) { + return; } + + const QPair error = SAVE_ERROR[result]; + GUI::showWarning(error.first, error.second); } void ProfileForm::onDeletePassClicked() { - Profile* pro = Nexus::getProfile(); - if (!pro->isEncrypted()) { + if (!profileInfo->isEncrypted()) { GUI::showInfo(tr("Nothing to remove"), tr("Your profile does not have a password!")); return; } - if (!GUI::askQuestion(tr("Really delete password?", "deletion confirmation title"), - tr("Are you sure you want to delete your password?", - "deletion confirmation text"))) + const QString title = tr("Really delete password?", "deletion confirmation title"); + //: deletion confirmation text + const QString body = tr("Are you sure you want to delete your password?"); + if (!GUI::askQuestion(title, body)) { return; + } - QString errorMsg = pro->setPassword(QString()); - if (!errorMsg.isEmpty()) { - GUI::showInfo(tr("Couldn't change password"), errorMsg); + if (!profileInfo->deletePassword()) { + GUI::showInfo(CAN_NOT_CHANGE_PASSWORD.first, CAN_NOT_CHANGE_PASSWORD.second); } } void ProfileForm::onChangePassClicked() { - Profile* p = Nexus::getProfile(); - SetPasswordDialog* dialog = - new SetPasswordDialog(tr("Please enter a new password."), QString(), 0); - int r = dialog->exec(); - if (r == QDialog::Rejected) + const QString title = tr("Please enter a new password."); + SetPasswordDialog* dialog = new SetPasswordDialog(title, QString{}, nullptr); + if (dialog->exec() == QDialog::Rejected) { return; + } QString newPass = dialog->getPassword(); - QString errorMsg = p->setPassword(newPass); - if (!errorMsg.isEmpty()) { - GUI::showInfo(tr("Couldn't change password"), errorMsg); + if (!profileInfo->setPassword(newPass)) { + GUI::showInfo(CAN_NOT_CHANGE_PASSWORD.first, CAN_NOT_CHANGE_PASSWORD.second); } } @@ -506,8 +503,9 @@ void ProfileForm::showExistingToxme() void ProfileForm::onRegisterButtonClicked() { QString name = bodyUI->toxmeUsername->text(); - if (name.isEmpty()) + if (name.isEmpty()) { return; + } bodyUI->toxmeRegisterButton->setEnabled(false); bodyUI->toxmeUpdateButton->setEnabled(false); diff --git a/src/widget/form/profileform.h b/src/widget/form/profileform.h index bd143ace5..3851b2a21 100644 --- a/src/widget/form/profileform.h +++ b/src/widget/form/profileform.h @@ -27,10 +27,10 @@ #include #include -class CroppingLabel; -class Core; -class MaskablePixmapWidget; class ContentLayout; +class CroppingLabel; +class IProfileInfo; +class MaskablePixmapWidget; namespace Ui { class IdentitySettings; @@ -54,7 +54,7 @@ class ProfileForm : public QWidget { Q_OBJECT public: - explicit ProfileForm(QWidget* parent = nullptr); + ProfileForm(IProfileInfo* profileInfo, QWidget* parent = nullptr); ~ProfileForm(); virtual void show() final { @@ -98,6 +98,7 @@ private: bool hasCheck = false; QRWidget* qr; ClickableTE* toxId; + IProfileInfo* profileInfo; void showRegisterToxme(); }; diff --git a/src/widget/widget.cpp b/src/widget/widget.cpp index 9418c6c19..b1a3f64dd 100644 --- a/src/widget/widget.cpp +++ b/src/widget/widget.cpp @@ -73,6 +73,8 @@ #include "src/widget/translator.h" #include "tool/removefrienddialog.h" +#include + bool toxActivateEventHandler(const QByteArray&) { Widget* widget = Nexus::getDesktopGUI(); @@ -228,12 +230,14 @@ void Widget::init() filesForm = new FilesForm(); addFriendForm = new AddFriendForm; groupInviteForm = new GroupInviteForm; - profileForm = new ProfileForm(); + + Profile* profile = Nexus::getProfile(); + profileInfo = new ProfileInfo(profile); + profileForm = new ProfileForm(profileInfo); // connect logout tray menu action connect(actionLogout, &QAction::triggered, profileForm, &ProfileForm::onLogoutClicked); - Profile* profile = Nexus::getProfile(); connect(profile, &Profile::selfAvatarChanged, profileForm, &ProfileForm::onSelfAvatarLoaded); const Settings& s = Settings::getInstance(); diff --git a/src/widget/widget.h b/src/widget/widget.h index ec74ed690..3e4c71de9 100644 --- a/src/widget/widget.h +++ b/src/widget/widget.h @@ -38,32 +38,33 @@ namespace Ui { class MainWindow; } +class AddFriendForm; +class Camera; class ChatForm; -class GenericChatroomWidget; +class CircleWidget; +class ContentDialog; +class ContentLayout; +class Core; +class FilesForm; +class Friend; +class FriendListWidget; class FriendWidget; -class GroupWidget; +class GenericChatroomWidget; class Group; class GroupInvite; -class Friend; -class QSplitter; -class VideoSurface; -class QMenu; -class Core; -class Camera; -class FriendListWidget; -class MaskablePixmapWidget; -class QTimer; -class SystemTrayIcon; -class FilesForm; -class ProfileForm; -class SettingsWidget; -class AddFriendForm; class GroupInviteForm; -class CircleWidget; +class GroupWidget; +class MaskablePixmapWidget; +class ProfileForm; +class ProfileInfo; class QActionGroup; -class ContentLayout; -class ContentDialog; +class QMenu; class QPushButton; +class QSplitter; +class QTimer; +class SettingsWidget; +class SystemTrayIcon; +class VideoSurface; class Widget final : public QMainWindow { @@ -276,7 +277,10 @@ private: ContentLayout* contentLayout; AddFriendForm* addFriendForm; GroupInviteForm* groupInviteForm; + + ProfileInfo* profileInfo; ProfileForm* profileForm; + QPointer settingsWidget; FilesForm* filesForm; static Widget* instance;