#include "./enterpassworddialog.h" #include "../misc/dialogutils.h" #include "ui_enterpassworddialog.h" #include #include #include #include #include #ifdef QT_UTILITIES_PLATFORM_SPECIFIC_CAPSLOCK_DETECTION # if defined(Q_OS_WIN32) # include # elif defined(X_AVAILABLE) # include # undef KeyPress # undef KeyRelease # undef FocusIn # undef FocusOut # endif #endif namespace Dialogs { /*! * \class Dialogs::EnterPasswordDialog * \brief The EnterPasswordDialog class provides a simple dialog to ask the user for a password. */ /*! * \brief Constructs a password dialog. * \param parent Specifies the parent widget. */ EnterPasswordDialog::EnterPasswordDialog(QWidget *parent) : QDialog(parent), m_ui(new Ui::EnterPasswordDialog) { // setup ui m_ui->setupUi(this); makeHeading(m_ui->instructionLabel); setStyleSheet(dialogStyle()); setDescription(); setPromptForUserName(false); setVerificationRequired(false); setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint); installEventFilter(this); m_ui->userNameLineEdit->installEventFilter(this); m_ui->password1LineEdit->installEventFilter(this); m_ui->password2LineEdit->installEventFilter(this); // capslock key detection #ifdef QT_UTILITIES_PLATFORM_SPECIFIC_CAPSLOCK_DETECTION m_capslockPressed = isCapslockPressed(); #else m_capslockPressed = false; #endif m_ui->capslockWarningWidget->setVisible(m_capslockPressed); // draw icon to capslock warning graphics view QIcon icon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxWarning, nullptr, this); QGraphicsScene* scene = new QGraphicsScene(); QGraphicsPixmapItem* item = new QGraphicsPixmapItem(icon.pixmap(16, 16)); scene->addItem(item); m_ui->capslockWarningGraphicsView->setScene(scene); // connect signals and slots connect(m_ui->showPasswordCheckBox, &QCheckBox::clicked, this, &EnterPasswordDialog::updateShowPassword); connect(m_ui->noPwCheckBox, &QCheckBox::clicked, this, &EnterPasswordDialog::updateShowPassword); connect(m_ui->confirmPushButton, &QPushButton::clicked, this, &EnterPasswordDialog::confirm); connect(m_ui->abortPushButton, &QPushButton::clicked, this, &EnterPasswordDialog::abort); // grab the keyboard grabKeyboard(); } /*! * \brief Destroys the password dialog. */ EnterPasswordDialog::~EnterPasswordDialog() {} /*! * \brief Returns the description. The description is shown under the instruction text. * \sa setDescription() */ QString EnterPasswordDialog::description() const { return m_ui->descLabel->text(); } /*! * \brief Sets the description. * \sa description() */ void EnterPasswordDialog::setDescription(const QString &description) { m_ui->descLabel->setText(description); m_ui->descLabel->setHidden(description.isEmpty()); adjustSize(); } /*! * \brief Returns whether the dialogs prompts for a user name as well. * * The dialog does not prompt for a user name by default. * * \sa setPromptForUserName() */ bool EnterPasswordDialog::promtForUserName() const { return !m_ui->userNameLineEdit->isHidden(); } /*! * \brief Sets whethere the dialog prompts for a user name as well. * \sa promptForUserName() */ void EnterPasswordDialog::setPromptForUserName(bool prompt) { m_ui->userNameLineEdit->setHidden(!prompt); adjustSize(); } /*! * \brief Returns an indication whether a verification (password has to be entered twice) is required. * * \sa EnterPasswordDialog::setVerificationRequired() */ bool EnterPasswordDialog::isVerificationRequired() const { return !m_ui->password2LineEdit->isHidden(); } /*! * \brief Returns an indication whether the user is force to enter a password. * * If no password is required, the user is allowed to skip the dialog without entering * a password. * * \sa EnterPasswordDialog::setPasswordRequired() */ bool EnterPasswordDialog::isPasswordRequired() const { return m_ui->noPwCheckBox->isHidden(); } /*! * \brief Sets whether the user is force to enter a password. * * If no password is required, the user is allowed to skip the dialog without entering * a password. * * \sa EnterPasswordDialog::isPasswordRequired() */ void EnterPasswordDialog::setPasswordRequired(bool value) { m_ui->noPwCheckBox->setHidden(value); m_ui->noPwCheckBox->setChecked(false); adjustSize(); } /*! * \brief Updates the relevant controls to show entered characters or to mask them them. * * This private slot is called when m_ui->showPasswordCheckBox is clicked. */ void EnterPasswordDialog::updateShowPassword() { m_ui->password1LineEdit->setEchoMode(m_ui->showPasswordCheckBox->isChecked() ? QLineEdit::Normal : QLineEdit::Password); m_ui->password1LineEdit->setEnabled(!m_ui->noPwCheckBox->isChecked()); m_ui->password2LineEdit->setEnabled(!(m_ui->showPasswordCheckBox->isChecked() || m_ui->noPwCheckBox->isChecked())); } /*! * \brief Sets whether a verification (password has to be entered twice) is required. * * \sa EnterPasswordDialog::isVerificationRequired() */ void EnterPasswordDialog::setVerificationRequired(bool value) { if(m_instruction.isEmpty()) { m_ui->instructionLabel->setText(value ? tr("Enter the new password") : tr("Enter the password")); } m_ui->password2LineEdit->setHidden(!value); adjustSize(); } /*! * \brief Sets the instruction text. * * \sa EnterPasswordDialog::instruction() */ void EnterPasswordDialog::setInstruction(const QString &value) { m_instruction = value; if(m_instruction.isEmpty()) { m_ui->instructionLabel->setText(isVerificationRequired() ? tr("Enter the new password") : tr("Enter the password")); } else { m_ui->instructionLabel->setText(value); } adjustSize(); } bool EnterPasswordDialog::event(QEvent *event) { switch(event->type()) { case QEvent::KeyPress: { QKeyEvent *keyEvent = static_cast(event); if(keyEvent->key() == Qt::Key_CapsLock) { m_capslockPressed = !m_capslockPressed; } m_ui->capslockWarningWidget->setVisible(m_capslockPressed); break; } default: ; } return QDialog::event(event); } /*! * \brief Internal method to notice when the capslock key is pressed by the user. * * Invocation of this method is done by installing the event filter in the constructor. */ bool EnterPasswordDialog::eventFilter(QObject *sender, QEvent *event) { switch(event->type()) { case QEvent::KeyPress: { QKeyEvent *keyEvent = static_cast(event); if(keyEvent->key() == Qt::Key_CapsLock) { m_capslockPressed = !m_capslockPressed; } else { QString text = keyEvent->text(); if(text.length()) { QChar firstChar = text.at(0); bool shiftPressed = (keyEvent->modifiers() & Qt::ShiftModifier) != 0; if((shiftPressed && firstChar.isLower()) || (!shiftPressed && firstChar.isUpper())) { m_capslockPressed = true; } else if(firstChar.isLetter()) { m_capslockPressed = false; } } } m_ui->capslockWarningWidget->setVisible(m_capslockPressed); } break; case QEvent::FocusIn: if(sender == m_ui->userNameLineEdit || sender == m_ui->password1LineEdit || sender == m_ui->password2LineEdit) { releaseKeyboard(); qobject_cast(sender)->grabKeyboard(); } break; case QEvent::FocusOut: if(sender == m_ui->userNameLineEdit || sender == m_ui->password1LineEdit || sender == m_ui->password2LineEdit) { qobject_cast(sender)->releaseKeyboard(); grabKeyboard(); } break; default: ; } return false; } /*! * \brief Sets the dialog status to QDialog::Accepted if a valid password has been enterd. * Displays an error message otherwise. * * This private slot is called when m_ui->confirmPushButton is clicked. */ void EnterPasswordDialog::confirm() { if(!isPasswordRequired() && m_ui->noPwCheckBox->isChecked()) { m_password.clear(); done(QDialog::Accepted); } else { QString userName = m_ui->userNameLineEdit->text(); QString password = m_ui->password1LineEdit->text(); QString repeatedPassword = m_ui->password2LineEdit->text(); if(promtForUserName() && userName.isEmpty()) { QMessageBox::warning(this, windowTitle(), tr("You didn't enter a user name.")); } else if(password.isEmpty()) { QMessageBox::warning(this, windowTitle(), tr("You didn't enter a password.")); } else { if(isVerificationRequired() && (password != repeatedPassword) && !m_ui->showPasswordCheckBox->isChecked()) { if(repeatedPassword.isEmpty()) { QMessageBox::warning(this, windowTitle(), tr("You have to enter the new password twice to ensure you enterd it correct.")); } else { QMessageBox::warning(this, windowTitle(), tr("You mistyped the password.")); } } else { m_userName = userName; m_password = password; done(QDialog::Accepted); } } } } /*! * \brief Returns an indication whether the capslock key is pressed using platform specific functions. * * \remarks - Returns always false for unsupported platforms. * - This method always returns false when not built with * QT_UTILITIES_PLATFORM_SPECIFIC_CAPSLOCK_DETECTION defined. * - This static function will be used internally to detect whether the capslock key is pressed * when initializing the dialog if available. * - The function requires the application to be linked against X11 on Linux/Unix. */ bool EnterPasswordDialog::isCapslockPressed() { #ifdef QT_UTILITIES_PLATFORM_SPECIFIC_CAPSLOCK_DETECTION // platform dependent method of determining if CAPS LOCK is pressed # if defined(Q_OS_WIN32) return GetKeyState(VK_CAPITAL) == 1; # elif defined(X_AVAILABLE) Display *d = XOpenDisplay((char*)0); bool caps_state = false; if (d) { unsigned n; XkbGetIndicatorState(d, XkbUseCoreKbd, &n); caps_state = (n & 0x01) == 1; } return caps_state; # else return false; # endif return false; #endif } }