diff --git a/autotests/CMakeLists.txt b/autotests/CMakeLists.txt index 41bb9f3..5f46b4c 100644 --- a/autotests/CMakeLists.txt +++ b/autotests/CMakeLists.txt @@ -1,33 +1,34 @@ include(ECMAddTests) find_package(Qt5 ${REQUIRED_QT_VERSION} CONFIG REQUIRED Test) ecm_add_tests( kcollapsiblegroupbox_test.cpp kcolorbuttontest.cpp kdatecomboboxtest.cpp kdatetimeedittest.cpp kdualactiontest.cpp kpixmapsequencewidgettest.cpp knewpasswordwidgettest.cpp kselectaction_unittest.cpp ktimecomboboxtest.cpp ktooltipwidgettest.cpp kmessagewidgetautotest.cpp kpagedialogautotest.cpp kpassworddialogautotest.cpp + kpasswordlineedittest.cpp ksplittercollapserbuttontest.cpp LINK_LIBRARIES Qt5::Test KF5::WidgetsAddons ) set (CMAKE_AUTOUIC TRUE) ecm_add_test( kcolumnresizertest.cpp kcolumnresizertest-forms.ui kcolumnresizertest-grids.ui kcolumnresizertest-grid-and-form.ui TEST_NAME kcolumnresizertest NAME_PREFIX "kwidgetsaddons-" LINK_LIBRARIES Qt5::Test KF5::WidgetsAddons ) diff --git a/autotests/knewpasswordwidgettest.cpp b/autotests/knewpasswordwidgettest.cpp index 59b1a0c..9421529 100644 --- a/autotests/knewpasswordwidgettest.cpp +++ b/autotests/knewpasswordwidgettest.cpp @@ -1,323 +1,325 @@ /* Copyright 2015 Elvis Angelaccio This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "knewpasswordwidgettest.h" #include #include #include #include +#include QTEST_MAIN(KNewPasswordWidgetTest) void KNewPasswordWidgetTest::testEmptyPasswordAllowed() { KNewPasswordWidget pwdWidget; QVERIFY(pwdWidget.allowEmptyPasswords()); QCOMPARE(pwdWidget.minimumPasswordLength(), 0); QCOMPARE(pwdWidget.passwordStatus(), KNewPasswordWidget::WeakPassword); } void KNewPasswordWidgetTest::testEmptyPasswordNotAllowed() { KNewPasswordWidget pwdWidget; pwdWidget.setAllowEmptyPasswords(false); QVERIFY(!pwdWidget.allowEmptyPasswords()); QCOMPARE(pwdWidget.minimumPasswordLength(), 1); QCOMPARE(pwdWidget.passwordStatus(), KNewPasswordWidget::EmptyPasswordNotAllowed); } void KNewPasswordWidgetTest::testPasswordTooShort() { KNewPasswordWidget pwdWidget; pwdWidget.setMinimumPasswordLength(5); - auto linePassword = pwdWidget.findChild(QStringLiteral("linePassword")); + auto linePassword = pwdWidget.findChild(QStringLiteral("linePassword")); auto lineVerifyPassword = pwdWidget.findChild(QStringLiteral("lineVerifyPassword")); QVERIFY(linePassword); QVERIFY(lineVerifyPassword); const QString password = QStringLiteral("1234"); - linePassword->setText(password); + //We can't use setPassword here as when we call it for security we don't allow to show password. So we need to use setText + linePassword->lineEdit()->setText(password); lineVerifyPassword->setText(password); QCOMPARE(pwdWidget.passwordStatus(), KNewPasswordWidget::PasswordTooShort); } void KNewPasswordWidgetTest::testPasswordMatch() { KNewPasswordWidget pwdWidget; - auto linePassword = pwdWidget.findChild(QStringLiteral("linePassword")); + auto linePassword = pwdWidget.findChild(QStringLiteral("linePassword")); auto lineVerifyPassword = pwdWidget.findChild(QStringLiteral("lineVerifyPassword")); QVERIFY(linePassword); QVERIFY(lineVerifyPassword); const QString password = QStringLiteral("1234"); - linePassword->setText(password); + linePassword->lineEdit()->setText(password); lineVerifyPassword->setText(password); QVERIFY(pwdWidget.passwordStatus() != KNewPasswordWidget::PasswordNotVerified); QCOMPARE(pwdWidget.password(), password); } void KNewPasswordWidgetTest::testPasswordNotVerified() { KNewPasswordWidget pwdWidget; - auto linePassword = pwdWidget.findChild(QStringLiteral("linePassword")); + auto linePassword = pwdWidget.findChild(QStringLiteral("linePassword")); QVERIFY(linePassword); const QString password = QStringLiteral("1234"); - linePassword->setText(password); + linePassword->lineEdit()->setText(password); QCOMPARE(pwdWidget.passwordStatus(), KNewPasswordWidget::PasswordNotVerified); } void KNewPasswordWidgetTest::testWeakPassword() { KNewPasswordWidget pwdWidget; pwdWidget.setPasswordStrengthWarningLevel(30 ); - auto linePassword = pwdWidget.findChild(QStringLiteral("linePassword")); + auto linePassword = pwdWidget.findChild(QStringLiteral("linePassword")); auto lineVerifyPassword = pwdWidget.findChild(QStringLiteral("lineVerifyPassword")); QVERIFY(linePassword); QVERIFY(lineVerifyPassword); const QString password = QStringLiteral("1234"); - linePassword->setText(password); + linePassword->lineEdit()->setText(password); lineVerifyPassword->setText(password); QCOMPARE(pwdWidget.passwordStatus(), KNewPasswordWidget::WeakPassword); } void KNewPasswordWidgetTest::testStrongPassword() { KNewPasswordWidget pwdWidget; pwdWidget.setPasswordStrengthWarningLevel(99); - auto linePassword = pwdWidget.findChild(QStringLiteral("linePassword")); + auto linePassword = pwdWidget.findChild(QStringLiteral("linePassword")); auto lineVerifyPassword = pwdWidget.findChild(QStringLiteral("lineVerifyPassword")); QVERIFY(linePassword); QVERIFY(lineVerifyPassword); const auto password = QStringLiteral("DHlKOJ1GotXWVE_fnqm1"); // generated by KeePass - linePassword->setText(password); + linePassword->lineEdit()->setText(password); lineVerifyPassword->setText(password); QCOMPARE(pwdWidget.passwordStatus(), KNewPasswordWidget::StrongPassword); } void KNewPasswordWidgetTest::testReasonablePasswordLength() { KNewPasswordWidget pwdWidget; pwdWidget.setReasonablePasswordLength(10); QCOMPARE(pwdWidget.reasonablePasswordLength(), 10); pwdWidget.setReasonablePasswordLength(0); QCOMPARE(pwdWidget.reasonablePasswordLength(), 1); pwdWidget.setReasonablePasswordLength(pwdWidget.maximumPasswordLength() + 1); QCOMPARE(pwdWidget.reasonablePasswordLength(), pwdWidget.maximumPasswordLength()); } void KNewPasswordWidgetTest::testPasswordStrengthWarningLevel() { KNewPasswordWidget pwdWidget; pwdWidget.setPasswordStrengthWarningLevel(40); QCOMPARE(pwdWidget.passwordStrengthWarningLevel(), 40); pwdWidget.setPasswordStrengthWarningLevel(-1); QCOMPARE(pwdWidget.passwordStrengthWarningLevel(), 0); pwdWidget.setPasswordStrengthWarningLevel(100); QCOMPARE(pwdWidget.passwordStrengthWarningLevel(), 99); } void KNewPasswordWidgetTest::testNoWarningColorBeforeMismatch() { KNewPasswordWidget pwdWidget; QColor defaultColor = pwdWidget.palette().color(QPalette::Base); QColor warningColor(Qt::red); pwdWidget.setBackgroundWarningColor(warningColor); - auto linePassword = pwdWidget.findChild(QStringLiteral("linePassword")); + auto linePassword = pwdWidget.findChild(QStringLiteral("linePassword")); auto lineVerifyPassword = pwdWidget.findChild(QStringLiteral("lineVerifyPassword")); QVERIFY(linePassword); QVERIFY(lineVerifyPassword); - linePassword->setText(QStringLiteral("1234")); + linePassword->lineEdit()->setText(QStringLiteral("1234")); QCOMPARE(lineVerifyPassword->palette().color(QPalette::Base), defaultColor); lineVerifyPassword->setText(QStringLiteral("12")); QCOMPARE(lineVerifyPassword->palette().color(QPalette::Base), defaultColor); } void KNewPasswordWidgetTest::testWarningColorIfMismatch() { KNewPasswordWidget pwdWidget; QColor defaultColor = pwdWidget.palette().color(QPalette::Base); QColor warningColor(Qt::red); pwdWidget.setBackgroundWarningColor(warningColor); - auto linePassword = pwdWidget.findChild(QStringLiteral("linePassword")); + auto linePassword = pwdWidget.findChild(QStringLiteral("linePassword")); auto lineVerifyPassword = pwdWidget.findChild(QStringLiteral("lineVerifyPassword")); QVERIFY(linePassword); QVERIFY(lineVerifyPassword); - linePassword->setText(QStringLiteral("1234")); + linePassword->lineEdit()->setText(QStringLiteral("1234")); QCOMPARE(lineVerifyPassword->palette().color(QPalette::Base), defaultColor); lineVerifyPassword->setText(QStringLiteral("122")); QCOMPARE(lineVerifyPassword->palette().color(QPalette::Base), warningColor); lineVerifyPassword->setText(QStringLiteral("1224")); QCOMPARE(lineVerifyPassword->palette().color(QPalette::Base), warningColor); } void KNewPasswordWidgetTest::testWarningColorPostMatch() { KNewPasswordWidget pwdWidget; QColor defaultColor = pwdWidget.palette().color(QPalette::Base); QColor warningColor(Qt::red); pwdWidget.setBackgroundWarningColor(warningColor); - auto linePassword = pwdWidget.findChild(QStringLiteral("linePassword")); + auto linePassword = pwdWidget.findChild(QStringLiteral("linePassword")); auto lineVerifyPassword = pwdWidget.findChild(QStringLiteral("lineVerifyPassword")); QVERIFY(linePassword); QVERIFY(lineVerifyPassword); - linePassword->setText(QStringLiteral("1234")); + linePassword->lineEdit()->setText(QStringLiteral("1234")); lineVerifyPassword->setText(QStringLiteral("1234")); QCOMPARE(lineVerifyPassword->palette().color(QPalette::Base), defaultColor); lineVerifyPassword->setText(QStringLiteral("12345")); QCOMPARE(lineVerifyPassword->palette().color(QPalette::Base), warningColor); } void KNewPasswordWidgetTest::disablingWidgetShouldUseDisabledPalette() { KNewPasswordWidget pwdWidget; - auto linePassword = pwdWidget.findChild(QStringLiteral("linePassword")); + auto linePassword = pwdWidget.findChild(QStringLiteral("linePassword")); auto lineVerifyPassword = pwdWidget.findChild(QStringLiteral("lineVerifyPassword")); QVERIFY(linePassword && linePassword->isEnabled()); QVERIFY(lineVerifyPassword && lineVerifyPassword->isEnabled()); pwdWidget.setEnabled(false); QVERIFY(!linePassword->isEnabled()); QVERIFY(!lineVerifyPassword->isEnabled()); QCOMPARE(linePassword->palette(), pwdWidget.palette()); QCOMPARE(lineVerifyPassword->palette(), pwdWidget.palette()); } void KNewPasswordWidgetTest::disablingParentShouldUseDisabledPalette() { auto widget = new QWidget(); widget->setEnabled(false); auto pwdWidget = new KNewPasswordWidget(widget); QVERIFY(!pwdWidget->isEnabled()); - auto linePassword = pwdWidget->findChild(QStringLiteral("linePassword")); + auto linePassword = pwdWidget->findChild(QStringLiteral("linePassword")); auto lineVerifyPassword = pwdWidget->findChild(QStringLiteral("lineVerifyPassword")); QVERIFY(linePassword && !linePassword->isEnabled()); QVERIFY(lineVerifyPassword && !lineVerifyPassword->isEnabled()); QCOMPARE(linePassword->palette(), widget->palette()); QCOMPARE(lineVerifyPassword->palette(), widget->palette()); delete widget; } void KNewPasswordWidgetTest::disablingRevealPasswordShouldHideVisibilityAction() { KNewPasswordWidget pwdWidget; - auto linePassword = pwdWidget.findChild(QStringLiteral("linePassword")); + auto linePassword = pwdWidget.findChild(QStringLiteral("linePassword")); QVERIFY(linePassword); auto visibilityAction = linePassword->findChild(QStringLiteral("visibilityAction")); QVERIFY(visibilityAction && !visibilityAction->isVisible()); - linePassword->setText(QStringLiteral("1234")); + linePassword->lineEdit()->setText(QStringLiteral("1234")); QVERIFY(visibilityAction->isVisible()); QCOMPARE(pwdWidget.isRevealPasswordAvailable(), visibilityAction->isVisible()); pwdWidget.setRevealPasswordAvailable(false); QVERIFY(!visibilityAction->isVisible()); QCOMPARE(pwdWidget.isRevealPasswordAvailable(), visibilityAction->isVisible()); } void KNewPasswordWidgetTest::shouldNotHideVisibilityActionInPlaintextMode() { KNewPasswordWidget pwdWidget; - auto linePassword = pwdWidget.findChild(QStringLiteral("linePassword")); + auto linePassword = pwdWidget.findChild(QStringLiteral("linePassword")); QVERIFY(linePassword); auto visibilityAction = linePassword->findChild(QStringLiteral("visibilityAction")); QVERIFY(visibilityAction && !visibilityAction->isVisible()); - linePassword->setText(QStringLiteral("1234")); + linePassword->lineEdit()->setText(QStringLiteral("1234")); QVERIFY(visibilityAction->isVisible()); visibilityAction->trigger(); linePassword->clear(); QVERIFY(visibilityAction->isVisible()); } void KNewPasswordWidgetTest::shouldHideVerificationLineEditInPlaintextMode() { KNewPasswordWidget pwdWidget; pwdWidget.show(); - auto linePassword = pwdWidget.findChild(QStringLiteral("linePassword")); + auto linePassword = pwdWidget.findChild(QStringLiteral("linePassword")); auto lineVerifyPassword = pwdWidget.findChild(QStringLiteral("lineVerifyPassword")); QVERIFY(linePassword); QVERIFY(lineVerifyPassword && lineVerifyPassword->isVisible()); auto visibilityAction = linePassword->findChild(QStringLiteral("visibilityAction")); QVERIFY(visibilityAction); - linePassword->setText(QStringLiteral("1234")); + linePassword->lineEdit()->setText(QStringLiteral("1234")); visibilityAction->trigger(); QVERIFY(!lineVerifyPassword->isVisible()); } diff --git a/autotests/kpassworddialogautotest.cpp b/autotests/kpassworddialogautotest.cpp index e4f6e06..aec8e57 100644 --- a/autotests/kpassworddialogautotest.cpp +++ b/autotests/kpassworddialogautotest.cpp @@ -1,47 +1,51 @@ /* Copyright 2017 Elvis Angelaccio This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kpassworddialogautotest.h" #include #include #include #include +#include QTEST_MAIN(KPasswordDialogAutotest) void KPasswordDialogAutotest::shouldNotHideVisibilityActionInPlaintextMode() { KPasswordDialog dialog; - auto linePassword = dialog.findChild(QStringLiteral("passEdit")); + auto linePassword = dialog.findChild(QStringLiteral("passEdit")); QVERIFY(linePassword); - auto visibilityAction = linePassword->findChild(QStringLiteral("visibilityAction")); + auto lineEdit = linePassword->lineEdit(); + QVERIFY(lineEdit); + + auto visibilityAction = lineEdit->findChild(QStringLiteral("visibilityAction")); QVERIFY(visibilityAction && !visibilityAction->isVisible()); - linePassword->setText(QStringLiteral("1234")); + linePassword->lineEdit()->setText(QStringLiteral("1234")); QVERIFY(visibilityAction->isVisible()); visibilityAction->trigger(); linePassword->clear(); QVERIFY(visibilityAction->isVisible()); } diff --git a/autotests/kpasswordlineedittest.cpp b/autotests/kpasswordlineedittest.cpp new file mode 100644 index 0000000..a1a39d6 --- /dev/null +++ b/autotests/kpasswordlineedittest.cpp @@ -0,0 +1,95 @@ +/* + Copyright (c) 2017 Montel Laurent + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2 of the License or + ( at your option ) version 3 or, at the discretion of KDE e.V. + ( which shall act as a proxy as in section 14 of the GPLv3 ), any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kpasswordlineedittest.h" +#include "kpasswordlineedit.h" +#include +#include +#include +#include + +PasswordLineEditTest::PasswordLineEditTest(QObject *parent) + : QObject(parent) +{ + +} + +void PasswordLineEditTest::shouldHaveDefaultValue() +{ + KPasswordLineEdit lineEdit; + QVERIFY(lineEdit.password().isEmpty()); + + QHBoxLayout *mainLayout = lineEdit.findChild(QStringLiteral("mainlayout")); + QVERIFY(mainLayout); + QCOMPARE(mainLayout->margin(), 0); + + QLineEdit *edit = lineEdit.findChild(QStringLiteral("passwordlineedit")); + QVERIFY(edit); + QVERIFY(edit->text().isEmpty()); + QCOMPARE(edit->echoMode(), QLineEdit::Password); + + QVERIFY(lineEdit.toggleEchoModeAction()); + QVERIFY(!lineEdit.toggleEchoModeAction()->isVisible()); +} + +void PasswordLineEditTest::shouldShowTogglePassword() +{ + KPasswordLineEdit lineEdit; + lineEdit.show(); + QTest::qWaitForWindowExposed(&lineEdit); + + QLineEdit *edit = lineEdit.findChild(QStringLiteral("passwordlineedit")); + edit->setText(QStringLiteral("FOO")); + QVERIFY(lineEdit.toggleEchoModeAction()->isVisible()); + + edit->clear(); + QVERIFY(!lineEdit.toggleEchoModeAction()->isVisible()); +} + +void PasswordLineEditTest::shouldNotShowToggleWhenSetPassword() +{ + KPasswordLineEdit lineEdit; + lineEdit.show(); + QTest::qWaitForWindowExposed(&lineEdit); + lineEdit.setPassword(QStringLiteral("foo")); + QVERIFY(!lineEdit.toggleEchoModeAction()->isVisible()); +} + +void PasswordLineEditTest::shouldShowRevealPassword() +{ + KPasswordLineEdit lineEdit; + lineEdit.show(); + QTest::qWaitForWindowExposed(&lineEdit); + + QLineEdit *edit = lineEdit.findChild(QStringLiteral("passwordlineedit")); + edit->setText(QStringLiteral("FOO")); + QVERIFY(lineEdit.toggleEchoModeAction()->isVisible()); + + lineEdit.setRevealPasswordAvailable(false); + QVERIFY(!lineEdit.toggleEchoModeAction()->isVisible()); + + lineEdit.setRevealPasswordAvailable(true); + QVERIFY(lineEdit.toggleEchoModeAction()->isVisible()); + + edit->clear(); + QVERIFY(!lineEdit.toggleEchoModeAction()->isVisible()); +} + +QTEST_MAIN(PasswordLineEditTest) diff --git a/autotests/kpasswordlineedittest.h b/autotests/kpasswordlineedittest.h new file mode 100644 index 0000000..2fbce10 --- /dev/null +++ b/autotests/kpasswordlineedittest.h @@ -0,0 +1,39 @@ +/* + Copyright (c) 2017 Montel Laurent + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2 of the License or + ( at your option ) version 3 or, at the discretion of KDE e.V. + ( which shall act as a proxy as in section 14 of the GPLv3 ), any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef PASSWORDLINEEDITTEST_H +#define PASSWORDLINEEDITTEST_H + +#include + +class PasswordLineEditTest : public QObject +{ + Q_OBJECT +public: + explicit PasswordLineEditTest(QObject *parent = nullptr); + ~PasswordLineEditTest() = default; +private Q_SLOTS: + void shouldHaveDefaultValue(); + void shouldShowTogglePassword(); + void shouldNotShowToggleWhenSetPassword(); + void shouldShowRevealPassword(); +}; + +#endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9c5858e..d78166c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,304 +1,307 @@ include(ECMPoQmTools) ecm_create_qm_loader(kwidgetsaddons_QM_LOADER kwidgetsaddons5_qt) qt5_add_resources(kwidgetsaddons_ICON_SRCS icons.qrc) set(kwidgetsaddons_SRCS kacceleratormanager.cpp kanimatedbutton.cpp kcharselect.cpp kcharselectdata.cpp kcollapsiblegroupbox.cpp kcolorbutton.cpp kcolumnresizer.cpp kdatecombobox.cpp kdatepicker.cpp kdatetable.cpp kdatetimeedit.cpp kfontaction.cpp knewpasswordwidget.cpp fonthelpers.cpp kfontsizeaction.cpp kpopupframe.cpp kselectaction.cpp ktimecombobox.cpp kdragwidgetdecorator.cpp kdualaction.cpp kfontchooser.cpp kguiitem.cpp kled.cpp kmessagebox.cpp kmessagebox_p.cpp kmultitabbar.cpp kstandardguiitem.cpp kurllabel.cpp # Not good enough quality. Needs to use QUrl instead of QString and should not inherit QLabel, but hold it as a member instead. kcapacitybar.cpp kfontrequester.cpp kpassworddialog.cpp kruler.cpp kselector.cpp kxyselector.cpp kseparator.cpp ksqueezedtextlabel.cpp ktitlewidget.cpp ktoggleaction.cpp ktogglefullscreenaction.cpp kviewstateserializer.cpp kviewstatemaintainerbase.cpp keditlistwidget.cpp kcursor.cpp kratingwidget.cpp kratingpainter.cpp kactionselector.cpp kcolorcombo.cpp ktoolbarspaceraction.cpp kpixmapregionselectordialog.cpp kpixmapregionselectorwidget.cpp kactionmenu.cpp ktoolbarlabelaction.cpp ktoolbarpopupaction.cpp kpagedialog.cpp kpagemodel.cpp kpageview.cpp kpageview_p.cpp kpagewidget.cpp kpagewidgetmodel.cpp kassistantdialog.cpp kmessagewidget.cpp knewpassworddialog.cpp lineediturldropeventfilter.cpp + kpasswordlineedit.cpp kpixmapsequence.cpp kpixmapsequenceoverlaypainter.cpp kpixmapsequencewidget.cpp kmimetypechooser.cpp kmimetypeeditor.cpp ksplittercollapserbutton.cpp kstyleextensions.cpp ktooltipwidget.cpp ${kwidgetsaddons_QM_LOADER} ${kwidgetsaddons_ICON_SRCS} ) set(kwidgetsaddon_UI kdatetimeedit.ui knewpassworddialog.ui knewpasswordwidget.ui kpassworddialog.ui ) qt5_wrap_ui(kwidgetsaddons_SRCS ${kwidgetsaddon_UI} ) ecm_qt_declare_logging_category(kwidgetsaddons_SRCS HEADER loggingcategory.h IDENTIFIER KWidgetsAddonsLog CATEGORY_NAME kf5.kwidgetsaddons DEFAULT_SEVERITY Warning ) add_library(KF5WidgetsAddons ${kwidgetsaddons_SRCS}) generate_export_header(KF5WidgetsAddons BASE_NAME KWidgetsAddons) add_library(KF5::WidgetsAddons ALIAS KF5WidgetsAddons) target_link_libraries(KF5WidgetsAddons PUBLIC Qt5::Widgets) target_include_directories(KF5WidgetsAddons INTERFACE "$") set_target_properties(KF5WidgetsAddons PROPERTIES VERSION ${KWIDGETSADDONS_VERSION_STRING} SOVERSION ${KWIDGETSADDONS_SOVERSION} EXPORT_NAME WidgetsAddons ) ecm_generate_headers(KWidgetsAddons_HEADERS HEADER_NAMES KAcceleratorManager KAnimatedButton KCharSelect KCollapsibleGroupBox KColorButton KColumnResizer KDateComboBox KDatePicker KDateTimeEdit KDragWidgetDecorator KDualAction KFontAction KFontChooser KFontSizeAction KGuiItem KLed KMessageBox KMessageBoxDontAskAgainInterface KMultiTabBar,KMultiTabBarButton,KMultiTabBarTab KNewPasswordWidget KPopupFrame KSelectAction KStandardGuiItem KTimeComboBox KUrlLabel KCapacityBar KFontRequester KPasswordDialog KRuler KSelector,KGradientSelector KTitleWidget KXYSelector KSeparator KSqueezedTextLabel KToggleAction KToggleFullScreenAction KViewStateSerializer KViewStateMaintainerBase KEditListWidget KCursor KRatingPainter KRatingWidget KActionSelector KColorCombo KActionMenu KToolBarLabelAction KToolBarPopupAction KToolBarSpacerAction KPageDialog KPageModel KPageView KPageWidget KPageWidgetModel,KPageWidgetItem KAssistantDialog KMessageWidget KNewPasswordDialog LineEditUrlDropEventFilter + KPasswordLineEdit KPixmapSequence KPixmapSequenceOverlayPainter KPixmapSequenceWidget KPixmapRegionSelectorDialog KPixmapRegionSelectorWidget KMimeTypeChooser,KMimeTypeChooserDialog KMimeTypeEditor KMessageBoxNotifyInterface KSplitterCollapserButton KStyleExtensions KToolTipWidget REQUIRED_HEADERS KWidgetsAddons_HEADERS ) find_package(PythonModuleGeneration) if (PythonModuleGeneration_FOUND) ecm_generate_python_binding( TARGET KF5::WidgetsAddons PYTHONNAMESPACE PyKF5 MODULENAME KWidgetsAddons RULES_FILE "${CMAKE_SOURCE_DIR}/cmake/rules_PyKF5.py" INSTALL_DIR_SUFFIX ${KDE_INSTALL_PYTHONBINDINGSDIR} SIP_DEPENDS QtWidgets/QtWidgetsmod.sip HEADERS kacceleratormanager.h kanimatedbutton.h kcharselect.h kcollapsiblegroupbox.h kcolorbutton.h kcolumnresizer.h kdatecombobox.h kdatepicker.h kdatetimeedit.h kdragwidgetdecorator.h kdualaction.h kfontaction.h kfontchooser.h kfontsizeaction.h kguiitem.h kled.h kmessagebox.h kmessageboxdontaskagaininterface.h kmultitabbar.h knewpasswordwidget.h kpopupframe.h kselectaction.h kstandardguiitem.h ktimecombobox.h kurllabel.h kcapacitybar.h kfontrequester.h kpassworddialog.h kruler.h kselector.h ktitlewidget.h kxyselector.h kseparator.h ksqueezedtextlabel.h ktoggleaction.h ktogglefullscreenaction.h kviewstateserializer.h kviewstatemaintainerbase.h keditlistwidget.h kcursor.h kratingpainter.h kratingwidget.h kactionselector.h kcolorcombo.h kactionmenu.h ktoolbarlabelaction.h ktoolbarpopupaction.h ktoolbarspaceraction.h kpagedialog.h kpagemodel.h kpageview.h kpagewidget.h kpagewidgetmodel.h kassistantdialog.h kmessagewidget.h knewpassworddialog.h lineediturldropeventfilter.h + kpasswordlineedit.h kpixmapsequence.h kpixmapsequenceoverlaypainter.h kpixmapsequencewidget.h kpixmapregionselectordialog.h kpixmapregionselectorwidget.h kmimetypechooser.h kmimetypeeditor.h kmessageboxnotifyinterface.h ksplittercollapserbutton.h kstyleextensions.h ) endif() install(TARGETS KF5WidgetsAddons EXPORT KF5WidgetsAddonsTargets ${KF5_INSTALL_TARGETS_DEFAULT_ARGS}) install(FILES ${KWidgetsAddons_HEADERS} ${CMAKE_CURRENT_BINARY_DIR}/kwidgetsaddons_export.h DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/KWidgetsAddons COMPONENT Devel ) install(FILES kcharselect-data DESTINATION ${KDE_INSTALL_DATADIR_KF5}/kcharselect) if (BUILD_QCH) ecm_add_qch( KF5WidgetsAddons_QCH NAME KWidgetsAddons BASE_NAME KF5WidgetsAddons VERSION ${KF5_VERSION} ORG_DOMAIN org.kde SOURCES # using only public headers, to cover only public API ${KWidgetsAddons_HEADERS} MD_MAINPAGE "${CMAKE_SOURCE_DIR}/README.md" IMAGE_DIRS "${CMAKE_SOURCE_DIR}/docs/pics" LINK_QCHS Qt5Core_QCH Qt5Gui_QCH Qt5Widgets_QCH BLANK_MACROS KWIDGETSADDONS_EXPORT KWIDGETSADDONS_DEPRECATED_EXPORT KWIDGETSADDONS_DEPRECATED TAGFILE_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR} QCH_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR} COMPONENT Devel ) endif() include(ECMGeneratePriFile) ecm_generate_pri_file(BASE_NAME KWidgetsAddons LIB_NAME KF5WidgetsAddons DEPS "widgets" FILENAME_VAR PRI_FILENAME INCLUDE_INSTALL_DIR ${KDE_INSTALL_INCLUDEDIR_KF5}/KWidgetsAddons) install(FILES ${PRI_FILENAME} DESTINATION ${ECM_MKSPECS_INSTALL_DIR}) diff --git a/src/knewpasswordwidget.cpp b/src/knewpasswordwidget.cpp index 828b98d..bc6341f 100644 --- a/src/knewpasswordwidget.cpp +++ b/src/knewpasswordwidget.cpp @@ -1,330 +1,309 @@ // vi: ts=8 sts=4 sw=4 /* This file is part of the KDE libraries Copyright (C) 1998 Pietro Iglio Copyright (C) 1999,2000 Geert Jansen Copyright (C) 2004,2005 Andrew Coles Copyright (C) 2007 Michaƫl Larouche Copyright (C) 2009 Christoph Feck Copyright (C) 2015 Elvis Angelaccio This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "knewpasswordwidget.h" #include "ui_knewpasswordwidget.h" class KNewPasswordWidget::KNewPasswordWidgetPrivate { public: KNewPasswordWidgetPrivate(KNewPasswordWidget *parent) : q(parent), passwordStatus(WeakPassword), minimumPasswordLength(0), passwordStrengthWarningLevel(1), reasonablePasswordLength(8), - revealPasswordAvailable(true), toggleEchoModeAction(nullptr) {} void init(); - void _k_textChanged(); + void _k_passwordChanged(); void _k_toggleEchoMode(); - void _k_showToggleEchoModeAction(const QString &text); int effectivePasswordLength(const QString &password); void updatePasswordStatus(PasswordStatus status); KNewPasswordWidget *q; PasswordStatus passwordStatus; int minimumPasswordLength; int passwordStrengthWarningLevel; int reasonablePasswordLength; - bool revealPasswordAvailable; QAction *toggleEchoModeAction; QColor backgroundWarningColor; QColor defaultBackgroundColor; Ui::KNewPasswordWidget ui; }; void KNewPasswordWidget::KNewPasswordWidgetPrivate::init() { ui.setupUi(q); const QString strengthBarWhatsThis(tr("The password strength meter gives an indication of the security " "of the password you have entered. To improve the strength of the password, try:" "
  • using a longer password;
  • " "
  • using a mixture of upper- and lower-case letters;
  • " "
  • using numbers or symbols, such as #, as well as letters.
", "@info:whatsthis")); ui.labelStrengthMeter->setWhatsThis(strengthBarWhatsThis); ui.strengthBar->setWhatsThis(strengthBarWhatsThis); - QIcon visibilityIcon = QIcon::fromTheme(QStringLiteral("visibility"), QIcon(QStringLiteral(":/icons/visibility.svg"))); - toggleEchoModeAction = ui.linePassword->addAction(visibilityIcon, QLineEdit::TrailingPosition); - toggleEchoModeAction->setObjectName(QStringLiteral("visibilityAction")); - toggleEchoModeAction->setVisible(false); - toggleEchoModeAction->setToolTip(tr("Change the visibility of the password")); - connect(toggleEchoModeAction, SIGNAL(triggered(bool)), q, SLOT(_k_toggleEchoMode())); + connect(ui.linePassword, SIGNAL(echoModeChanged(QLineEdit::EchoMode)), q, SLOT(_k_toggleEchoMode())); - connect(ui.linePassword, SIGNAL(textChanged(QString)), q, SLOT(_k_showToggleEchoModeAction(QString))); - connect(ui.linePassword, SIGNAL(textChanged(QString)), q, SLOT(_k_textChanged())); - connect(ui.lineVerifyPassword, SIGNAL(textChanged(QString)), q, SLOT(_k_textChanged())); + connect(ui.linePassword, SIGNAL(passwordChanged(QString)), q, SLOT(_k_passwordChanged())); + connect(ui.lineVerifyPassword, SIGNAL(textChanged(QString)), q, SLOT(_k_passwordChanged())); defaultBackgroundColor = q->palette().color(QPalette::Active, QPalette::Base); backgroundWarningColor = defaultBackgroundColor; - _k_textChanged(); + _k_passwordChanged(); } -void KNewPasswordWidget::KNewPasswordWidgetPrivate::_k_textChanged() +void KNewPasswordWidget::KNewPasswordWidgetPrivate::_k_passwordChanged() { - const QString password = ui.linePassword->text(); + const QString password = ui.linePassword->password(); const QString verification = ui.lineVerifyPassword->text(); const bool match = (password == verification); const bool partialMatch = password.startsWith(verification); const int minPasswordLength = q->minimumPasswordLength(); QPalette palette = q->palette(); palette.setColor(QPalette::Active, QPalette::Base, (match || partialMatch) ? defaultBackgroundColor : backgroundWarningColor); ui.lineVerifyPassword->setPalette(palette); // Password strength calculator - int pwstrength = (20 * ui.linePassword->text().length() + 80 * effectivePasswordLength(ui.linePassword->text())) / qMax(reasonablePasswordLength, 2); + int pwstrength = (20 * ui.linePassword->password().length() + 80 * effectivePasswordLength(ui.linePassword->password())) / qMax(reasonablePasswordLength, 2); ui.strengthBar->setValue(qBound(0, pwstrength, 100)); // update the current password status if (match || ui.lineVerifyPassword->isHidden()) { - if (!q->allowEmptyPasswords() && ui.linePassword->text().isEmpty()) { + if (!q->allowEmptyPasswords() && ui.linePassword->password().isEmpty()) { updatePasswordStatus(EmptyPasswordNotAllowed); - } else if (ui.linePassword->text().length() < minPasswordLength) { + } else if (ui.linePassword->password().length() < minPasswordLength) { updatePasswordStatus(PasswordTooShort); } else if (ui.strengthBar && ui.strengthBar->value() < passwordStrengthWarningLevel) { updatePasswordStatus(WeakPassword); } else { updatePasswordStatus(StrongPassword); } } else { updatePasswordStatus(PasswordNotVerified); } } void KNewPasswordWidget::KNewPasswordWidgetPrivate::_k_toggleEchoMode() { - if (ui.linePassword->echoMode() == QLineEdit::Password) { - ui.linePassword->setEchoMode(QLineEdit::Normal); + if (ui.linePassword->lineEdit()->echoMode() == QLineEdit::Normal) { ui.lineVerifyPassword->hide(); ui.labelVerifyPassword->hide(); - toggleEchoModeAction->setIcon(QIcon::fromTheme(QStringLiteral("hint"), QIcon(QStringLiteral(":/icons/hint.svg")))); - } else if (ui.linePassword->echoMode() == QLineEdit::Normal) { - ui.linePassword->setEchoMode(QLineEdit::Password); + } else if (ui.linePassword->lineEdit()->echoMode() == QLineEdit::Password) { ui.lineVerifyPassword->show(); ui.labelVerifyPassword->show(); - toggleEchoModeAction->setIcon(QIcon::fromTheme(QStringLiteral("visibility"), QIcon(QStringLiteral(":/icons/visibility.svg")))); } - - _k_textChanged(); -} - -void KNewPasswordWidget::KNewPasswordWidgetPrivate::_k_showToggleEchoModeAction(const QString &text) -{ - toggleEchoModeAction->setVisible(revealPasswordAvailable && (ui.linePassword->echoMode() == QLineEdit::Normal || !text.isEmpty())); + _k_passwordChanged(); } int KNewPasswordWidget::KNewPasswordWidgetPrivate::effectivePasswordLength(const QString &password) { enum Category { Digit, Upper, Vowel, Consonant, Special }; Category previousCategory = Vowel; QString vowels(QStringLiteral("aeiou")); int count = 0; for (int i = 0; i < password.length(); ++i) { QChar currentChar = password.at(i); if (!password.leftRef(i).contains(currentChar)) { Category currentCategory; switch (currentChar.category()) { case QChar::Letter_Uppercase: currentCategory = Upper; break; case QChar::Letter_Lowercase: if (vowels.contains(currentChar)) { currentCategory = Vowel; } else { currentCategory = Consonant; } break; case QChar::Number_DecimalDigit: currentCategory = Digit; break; default: currentCategory = Special; break; } switch (currentCategory) { case Vowel: if (previousCategory != Consonant) { ++count; } break; case Consonant: if (previousCategory != Vowel) { ++count; } break; default: if (previousCategory != currentCategory) { ++count; } break; } previousCategory = currentCategory; } } return count; } void KNewPasswordWidget::KNewPasswordWidgetPrivate::updatePasswordStatus(PasswordStatus status) { if (passwordStatus == status) { return; } passwordStatus = status; emit q->passwordStatusChanged(); } KNewPasswordWidget::KNewPasswordWidget(QWidget *parent) : QWidget(parent), d(new KNewPasswordWidgetPrivate(this)) { d->init(); } KNewPasswordWidget::~KNewPasswordWidget() { delete d; } KNewPasswordWidget::PasswordStatus KNewPasswordWidget::passwordStatus() const { return d->passwordStatus; } bool KNewPasswordWidget::allowEmptyPasswords() const { return d->minimumPasswordLength == 0; } int KNewPasswordWidget::minimumPasswordLength() const { return d->minimumPasswordLength; } int KNewPasswordWidget::maximumPasswordLength() const { - return d->ui.linePassword->maxLength(); + return d->ui.linePassword->lineEdit()->maxLength(); } int KNewPasswordWidget::reasonablePasswordLength() const { return d->reasonablePasswordLength; } int KNewPasswordWidget::passwordStrengthWarningLevel() const { return d->passwordStrengthWarningLevel; } QColor KNewPasswordWidget::backgroundWarningColor() const { return d->backgroundWarningColor; } bool KNewPasswordWidget::isPasswordStrengthMeterVisible() const { return d->ui.labelStrengthMeter->isVisible() && d->ui.strengthBar->isVisible(); } bool KNewPasswordWidget::isRevealPasswordAvailable() const { - return d->revealPasswordAvailable; + return d->ui.linePassword->isRevealPasswordAvailable(); } QString KNewPasswordWidget::password() const { - return d->ui.linePassword->text(); + return d->ui.linePassword->password(); } void KNewPasswordWidget::setAllowEmptyPasswords(bool allowed) { setMinimumPasswordLength(allowed ? 0 : 1); - d->_k_textChanged(); + d->_k_passwordChanged(); } void KNewPasswordWidget::setMinimumPasswordLength(int minLength) { d->minimumPasswordLength = minLength; - d->_k_textChanged(); + d->_k_passwordChanged(); } void KNewPasswordWidget::setMaximumPasswordLength(int maxLength) { if (maxLength < minimumPasswordLength()) { maxLength = minimumPasswordLength(); } - d->ui.linePassword->setMaxLength(maxLength); + d->ui.linePassword->lineEdit()->setMaxLength(maxLength); d->ui.lineVerifyPassword->setMaxLength(maxLength); } // reasonable password length code contributed by Steffen Mthing void KNewPasswordWidget::setReasonablePasswordLength(int reasonableLength) { d->reasonablePasswordLength = qBound(1, reasonableLength, maximumPasswordLength()); } void KNewPasswordWidget::setPasswordStrengthWarningLevel(int warningLevel) { d->passwordStrengthWarningLevel = qBound(0, warningLevel, 99); } void KNewPasswordWidget::setBackgroundWarningColor(const QColor &color) { d->backgroundWarningColor = color; update(); } void KNewPasswordWidget::setPasswordStrengthMeterVisible(bool visible) { d->ui.labelStrengthMeter->setVisible(visible); d->ui.strengthBar->setVisible(visible); } void KNewPasswordWidget::setRevealPasswordAvailable(bool reveal) { - d->revealPasswordAvailable = reveal; - // Force update, we might already have shown the action. - d->_k_showToggleEchoModeAction(password()); + d->ui.linePassword->setRevealPasswordAvailable(reveal); } #include "moc_knewpasswordwidget.cpp" diff --git a/src/knewpasswordwidget.h b/src/knewpasswordwidget.h index 62907ae..969a41e 100644 --- a/src/knewpasswordwidget.h +++ b/src/knewpasswordwidget.h @@ -1,262 +1,261 @@ // vi: ts=8 sts=4 sw=4 /* This file is part of the KDE libraries Copyright (C) 1998 Pietro Iglio Copyright (C) 1999,2000 Geert Jansen Copyright (C) 2004,2005 Andrew Coles Copyright (C) 2006,2007 Olivier Goffart Copyright (C) 2015 Elvis Angelaccio This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KNEWPASSWORDWIDGET_H #define KNEWPASSWORDWIDGET_H #include #include /** * @class KNewPasswordWidget knewpasswordwidget.h KNewPasswordWidget * * @short A password input widget. * * This widget allows the user to enter a new password. * * The password has to be entered twice to check if the passwords * match. A hint about the strength of the entered password is also * shown. * * In order to embed this widget in your custom password dialog, * you may want to connect to the passwordStatus() signal. * This way you can e.g. disable the OK button if the passwords * don't match, warn the user if the password is too weak, and so on. * * \section usage Usage Example * \subsection Setup * * \code * KNewPasswordWidget *m_passwordWidget = new KNewPasswordWidget(this); * // set a background warning color (taken from the current color scheme) * KColorScheme colorScheme(QPalette::Active, KColorScheme::View); * m_passwordWidget->setBackgroundWarningColor(colorScheme.background(KColorScheme::NegativeBackground).color()); * // listen to password status updates * connect(m_passwordWidget, &KNewPasswordWidget::passwordStatusChanged, this, &MyCustomDialog::slotPasswordStatusChanged); * ... * \endcode * * \subsection update Update your custom dialog * * @snippet knewpasswordwidget_test.cpp update_custom_dialog * * \subsection accept Accept your custom dialog * * @snippet knewpasswordwidget_test.cpp accept_custom_dialog * * @author Geert Jansen * @author Olivier Goffart * @author Elvis Angelaccio * @since 5.16 */ class KWIDGETSADDONS_EXPORT KNewPasswordWidget : public QWidget { Q_OBJECT Q_PROPERTY(PasswordStatus passwordStatus READ passwordStatus) Q_PROPERTY(bool allowEmptyPasswords READ allowEmptyPasswords WRITE setAllowEmptyPasswords) Q_PROPERTY(int minimumPasswordLength READ minimumPasswordLength WRITE setMinimumPasswordLength) Q_PROPERTY(int maximumPasswordLength READ maximumPasswordLength WRITE setMaximumPasswordLength) Q_PROPERTY(int reasonablePasswordLength READ reasonablePasswordLength WRITE setReasonablePasswordLength) Q_PROPERTY(int passwordStrengthWarningLevel READ passwordStrengthWarningLevel WRITE setPasswordStrengthWarningLevel) Q_PROPERTY(QColor backgroundWarningColor READ backgroundWarningColor WRITE setBackgroundWarningColor) Q_PROPERTY(bool passwordStrengthMeterVisible READ isPasswordStrengthMeterVisible WRITE setPasswordStrengthMeterVisible) /** * @since 5.31 */ Q_PROPERTY(bool revealPasswordAvailable READ isRevealPasswordAvailable WRITE setRevealPasswordAvailable) public: /** * Status of the password being typed in the widget. */ enum PasswordStatus { EmptyPasswordNotAllowed, /**< Both passwords fields empty, but minimum length > 0. */ PasswordTooShort, /**< Password length is too low. */ PasswordNotVerified, /**< Password and verification password don't match. */ WeakPassword, /**< Passwords match but the strength level is not enough. */ StrongPassword, /**< Passwords match and the strength level is good. */ }; Q_ENUM(PasswordStatus) /** * Constructs a password widget. * * @param parent Passed to lower level constructor. */ explicit KNewPasswordWidget(QWidget *parent = nullptr); /** * Destructs the password widget. */ virtual ~KNewPasswordWidget(); /** * The current status of the password in the widget. */ PasswordStatus passwordStatus() const; /** * Allow empty passwords? * * @return true if minimumPasswordLength() == 0 */ bool allowEmptyPasswords() const; /** * Minimum acceptable password length. */ int minimumPasswordLength() const; /** * Maximum acceptable password length. */ int maximumPasswordLength() const; /** * Password length that is expected to be reasonably safe. */ int reasonablePasswordLength() const; /** * Password strength level below which a warning is given */ int passwordStrengthWarningLevel() const; /** * The color used as warning for the verification password field's background. */ QColor backgroundWarningColor() const; /** * Whether the password strength meter is visible. */ bool isPasswordStrengthMeterVisible() const; /** * Whether the visibility trailing action in the line edit is visible. * @since 5.31 */ bool isRevealPasswordAvailable() const; /** * Returns the password entered. * @note Only returns meaningful data when passwordStatus * is either WeakPassword or StrongPassword. */ QString password() const; public Q_SLOTS: /** * Allow empty passwords? - Default: true * * same as setMinimumPasswordLength( allowed ? 0 : 1 ) */ void setAllowEmptyPasswords(bool allowed); /** * Minimum acceptable password length. * * Default: 0 * * @param minLength The new minimum password length */ void setMinimumPasswordLength(int minLength); /** * Maximum acceptable password length. * * @param maxLength The new maximum password length. */ void setMaximumPasswordLength(int maxLength); /** * Password length that is expected to be reasonably safe. * The value is guaranteed to be in the range from 1 to maximumPasswordLength(). * * Used to compute the strength level * * Default: 8 - the standard UNIX password length * * @param reasonableLength The new reasonable password length. */ void setReasonablePasswordLength(int reasonableLength); /** * Set the password strength level below which a warning is given * The value is guaranteed to be in the range from 0 to 99. Empty passwords score 0; * non-empty passwords score up to 100, depending on their length and whether they * contain numbers, mixed case letters and punctuation. * * Default: 1 - warn if the password has no discernable strength whatsoever * @param warningLevel The level below which a warning should be given. */ void setPasswordStrengthWarningLevel(int warningLevel); /** * When the verification password does not match, the background color * of the verification field is set to @p color. As soon as the passwords match, * the original color of the verification field is restored. */ void setBackgroundWarningColor(const QColor &color); /** * Whether to show the password strength meter (label and progress bar). * Default is true. */ void setPasswordStrengthMeterVisible(bool visible); /** * Whether to show the visibility trailing action in the line edit. * Default is true. This can be used to honor the lineedit_reveal_password * kiosk key, for example: * \code * passwordWidget.setRevealPasswordAvailable(KAuthorized::authorize(QStringLiteral("lineedit_reveal_password"))); * \endcode * @since 5.31 */ void setRevealPasswordAvailable(bool reveal); Q_SIGNALS: /** * Notify about the current status of the password being typed. */ void passwordStatusChanged(); private: class KNewPasswordWidgetPrivate; KNewPasswordWidgetPrivate *const d; - Q_PRIVATE_SLOT(d, void _k_textChanged()) + Q_PRIVATE_SLOT(d, void _k_passwordChanged()) Q_PRIVATE_SLOT(d, void _k_toggleEchoMode()) - Q_PRIVATE_SLOT(d, void _k_showToggleEchoModeAction(const QString &text)) Q_DISABLE_COPY(KNewPasswordWidget) }; #endif // KNEWPASSWORDWIDGET_H diff --git a/src/knewpasswordwidget.ui b/src/knewpasswordwidget.ui index 4e5f795..9eb0c20 100644 --- a/src/knewpasswordwidget.ui +++ b/src/knewpasswordwidget.ui @@ -1,87 +1,91 @@ KNewPasswordWidget 0 0 273 - 127 + 130 Password: linePassword &Verify: lineVerifyPassword - - - QLineEdit::Password - + QLineEdit::Password Password strength &meter: strengthBar 0 false Qt::Vertical + + + KPasswordLineEdit + QWidget +
kpasswordlineedit.h
+
+
diff --git a/src/kpassworddialog.cpp b/src/kpassworddialog.cpp index 970bbce..a38c453 100644 --- a/src/kpassworddialog.cpp +++ b/src/kpassworddialog.cpp @@ -1,445 +1,413 @@ /* This file is part of the KDE libraries Copyright (C) 2000 David Faure Copyright (C) 2007 Olivier Goffart This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kpassworddialog.h" #include #include #include #include #include #include #include #include #include #include #include "ui_kpassworddialog.h" /** @internal */ class KPasswordDialog::KPasswordDialogPrivate { public: KPasswordDialogPrivate(KPasswordDialog *q) : q(q), userEditCombo(nullptr), pixmapLabel(nullptr), - commentRow(0), - isToggleEchoModeAvailable(true) + commentRow(0) {} void actuallyAccept(); void activated(const QString &userName); void updateFields(); void init(); - void toggleEchoMode(); - void showToggleEchoModeAction(const QString &text); - KPasswordDialog *q; Ui_KPasswordDialog ui; QMap knownLogins; QComboBox *userEditCombo; QLabel *pixmapLabel; KPasswordDialogFlags m_flags; unsigned int commentRow; - QAction *toggleEchoModeAction; - bool isToggleEchoModeAvailable; }; KPasswordDialog::KPasswordDialog(QWidget *parent, const KPasswordDialogFlags &flags) : QDialog(parent), d(new KPasswordDialogPrivate(this)) { setWindowTitle(tr("Password")); setWindowIcon(QIcon::fromTheme(QStringLiteral("dialog-password"), windowIcon())); d->m_flags = flags; d->init(); } KPasswordDialog::~KPasswordDialog() { delete d; } void KPasswordDialog::KPasswordDialogPrivate::updateFields() { if (m_flags & KPasswordDialog::UsernameReadOnly) { ui.userEdit->setReadOnly(true); ui.credentialsGroup->setFocusProxy(ui.passEdit); } ui.domainEdit->setReadOnly((m_flags & KPasswordDialog::DomainReadOnly)); ui.credentialsGroup->setEnabled(!q->anonymousMode()); } void KPasswordDialog::KPasswordDialogPrivate::init() { ui.setupUi(q); ui.buttonBox->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); ui.errorMessage->setHidden(true); // Row 4: Username field if (m_flags & KPasswordDialog::ShowUsernameLine) { ui.userEdit->setFocus(); ui.credentialsGroup->setFocusProxy(ui.userEdit); QObject::connect(ui.userEdit, SIGNAL(returnPressed()), ui.passEdit, SLOT(setFocus())); } else { ui.userNameLabel->hide(); ui.userEdit->hide(); ui.domainLabel->hide(); ui.domainEdit->hide(); ui.passEdit->setFocus(); ui.credentialsGroup->setFocusProxy(ui.passEdit); } if (!(m_flags & KPasswordDialog::ShowAnonymousLoginCheckBox)) { ui.anonymousRadioButton->hide(); ui.usePasswordButton->hide(); } if (!(m_flags & KPasswordDialog::ShowDomainLine)) { ui.domainLabel->hide(); ui.domainEdit->hide(); } if (!(m_flags & KPasswordDialog::ShowKeepPassword)) { ui.keepCheckBox->hide(); } updateFields(); - QIcon visibilityIcon = QIcon::fromTheme(QStringLiteral("visibility"), QIcon(QStringLiteral(":/icons/visibility.svg"))); - toggleEchoModeAction = ui.passEdit->addAction(visibilityIcon, QLineEdit::TrailingPosition); - toggleEchoModeAction->setObjectName(QStringLiteral("visibilityAction")); - toggleEchoModeAction->setVisible(false); - toggleEchoModeAction->setToolTip(tr("Change the visibility of the password")); - connect(toggleEchoModeAction, SIGNAL(triggered(bool)), q, SLOT(toggleEchoMode())); - connect(ui.passEdit, SIGNAL(textChanged(QString)), q, SLOT(showToggleEchoModeAction(QString))); - QRect desktop = QApplication::desktop()->screenGeometry(q->topLevelWidget()); q->setMinimumWidth(qMin(1000, qMax(q->sizeHint().width(), desktop.width() / 4))); QStyleOption option; option.initFrom(q); const int iconSize = q->style()->pixelMetric(QStyle::PM_MessageBoxIconSize, &option, q); q->setPixmap(QIcon::fromTheme(QStringLiteral("dialog-password")).pixmap(iconSize)); } -void KPasswordDialog::KPasswordDialogPrivate::toggleEchoMode() -{ - if (ui.passEdit->echoMode() == QLineEdit::Password) { - ui.passEdit->setEchoMode(QLineEdit::Normal); - toggleEchoModeAction->setIcon(QIcon::fromTheme(QStringLiteral("hint"), QIcon(QStringLiteral(":/icons/hint.svg")))); - } - else if (ui.passEdit->echoMode() == QLineEdit::Normal) { - ui.passEdit->setEchoMode(QLineEdit::Password); - toggleEchoModeAction->setIcon(QIcon::fromTheme(QStringLiteral("visibility"), QIcon(QStringLiteral(":/icons/visibility.svg")))); - } -} - -void KPasswordDialog::KPasswordDialogPrivate::showToggleEchoModeAction(const QString &text) -{ - toggleEchoModeAction->setVisible(isToggleEchoModeAvailable && (ui.passEdit->echoMode() == QLineEdit::Normal || !text.isEmpty())); -} - void KPasswordDialog::setPixmap(const QPixmap &pixmap) { if (!d->pixmapLabel) { d->pixmapLabel = new QLabel(this); d->pixmapLabel->setAlignment(Qt::AlignLeft | Qt::AlignTop); d->ui.hboxLayout->insertWidget(0, d->pixmapLabel); } d->pixmapLabel->setPixmap(pixmap); } QPixmap KPasswordDialog::pixmap() const { if (!d->pixmapLabel) { return QPixmap(); } return *d->pixmapLabel->pixmap(); } void KPasswordDialog::setUsername(const QString &user) { d->ui.userEdit->setText(user); if (user.isEmpty()) { return; } d->activated(user); if (d->ui.userEdit->isVisibleTo(this)) { d->ui.passEdit->setFocus(); } } QString KPasswordDialog::username() const { return d->ui.userEdit->text(); } QString KPasswordDialog::password() const { - return d->ui.passEdit->text(); + return d->ui.passEdit->password(); } void KPasswordDialog::setDomain(const QString &domain) { d->ui.domainEdit->setText(domain); } QString KPasswordDialog::domain() const { return d->ui.domainEdit->text(); } void KPasswordDialog::setAnonymousMode(bool anonymous) { if (anonymous && !(d->m_flags & KPasswordDialog::ShowAnonymousLoginCheckBox)) { // This is an error case, but we can at least let user see what's about // to happen if they proceed. d->ui.anonymousRadioButton->setVisible(true); d->ui.usePasswordButton->setVisible(true); d->ui.usePasswordButton->setEnabled(false); } d->ui.anonymousRadioButton->setChecked(anonymous); } bool KPasswordDialog::anonymousMode() const { return d->ui.anonymousRadioButton->isChecked(); } void KPasswordDialog::setKeepPassword(bool b) { d->ui.keepCheckBox->setChecked(b); } bool KPasswordDialog::keepPassword() const { return d->ui.keepCheckBox->isChecked(); } void KPasswordDialog::addCommentLine(const QString &label, const QString &comment) { int gridMarginLeft, gridMarginTop, gridMarginRight, gridMarginBottom; d->ui.formLayout->getContentsMargins(&gridMarginLeft, &gridMarginTop, &gridMarginRight, &gridMarginBottom); int spacing = d->ui.formLayout->horizontalSpacing(); if (spacing < 0) { // same inter-column spacing for all rows, see comment in qformlayout.cpp spacing = style()->combinedLayoutSpacing(QSizePolicy::Label, QSizePolicy::LineEdit, Qt::Horizontal, nullptr, this); } QLabel *c = new QLabel(comment, this); c->setWordWrap(true); d->ui.formLayout->insertRow(d->commentRow, label, c); ++d->commentRow; // cycle through column 0 widgets and see the max width so we can set the minimum height of // column 2 wordwrapable labels int firstColumnWidth = 0; for (int i = 0; i < d->ui.formLayout->rowCount(); ++i) { QLayoutItem *li = d->ui.formLayout->itemAt(i, QFormLayout::LabelRole); if (li) { QWidget *w = li->widget(); if (w && !w->isHidden()) { firstColumnWidth = qMax(firstColumnWidth, w->sizeHint().width()); } } } for (int i = 0; i < d->ui.formLayout->rowCount(); ++i) { QLayoutItem *li = d->ui.formLayout->itemAt(i, QFormLayout::FieldRole); if (li) { QLabel *l = qobject_cast(li->widget()); if (l && l->wordWrap()) { const int marginHint = style()->pixelMetric(QStyle::PM_DefaultChildMargin); int w = sizeHint().width() - firstColumnWidth - (2 * marginHint) - gridMarginLeft - gridMarginRight - spacing; l->setMinimumSize(w, l->heightForWidth(w)); } } } } void KPasswordDialog::showErrorMessage(const QString &message, const ErrorType type) { d->ui.errorMessage->setText(message, KTitleWidget::ErrorMessage); QFont bold = font(); bold.setBold(true); switch (type) { case PasswordError: d->ui.passwordLabel->setFont(bold); d->ui.passEdit->clear(); d->ui.passEdit->setFocus(); break; case UsernameError: if (d->ui.userEdit->isVisibleTo(this)) { d->ui.userNameLabel->setFont(bold); d->ui.userEdit->setFocus(); } break; case DomainError: if (d->ui.domainEdit->isVisibleTo(this)) { d->ui.domainLabel->setFont(bold); d->ui.domainEdit->setFocus(); } break; case FatalError: d->ui.userNameLabel->setEnabled(false); d->ui.userEdit->setEnabled(false); d->ui.passwordLabel->setEnabled(false); d->ui.passEdit->setEnabled(false); d->ui.keepCheckBox->setEnabled(false); d->ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); break; default: break; } adjustSize(); } void KPasswordDialog::setPrompt(const QString &prompt) { d->ui.prompt->setText(prompt); d->ui.prompt->setWordWrap(true); const int marginHint = style()->pixelMetric(QStyle::PM_DefaultChildMargin); d->ui.prompt->setMinimumHeight(d->ui.prompt->heightForWidth(width() - (2 * marginHint))); } QString KPasswordDialog::prompt() const { return d->ui.prompt->text(); } void KPasswordDialog::setPassword(const QString &p) { - d->isToggleEchoModeAvailable = p.isEmpty(); - d->ui.passEdit->setText(p); + d->ui.passEdit->setPassword(p); } void KPasswordDialog::setUsernameReadOnly(bool readOnly) { d->ui.userEdit->setReadOnly(readOnly); if (readOnly && d->ui.userEdit->hasFocus()) { d->ui.passEdit->setFocus(); } } void KPasswordDialog::setKnownLogins(const QMap &knownLogins) { const int nr = knownLogins.count(); if (nr == 0) { return; } if (nr == 1) { d->ui.userEdit->setText(knownLogins.begin().key()); setPassword(knownLogins.begin().value()); return; } Q_ASSERT(!d->ui.userEdit->isReadOnly()); if (!d->userEditCombo) { int row = -1; QFormLayout::ItemRole userEditRole = QFormLayout::FieldRole; d->ui.formLayout->getWidgetPosition(d->ui.userEdit, &row, &userEditRole); d->ui.formLayout->removeWidget(d->ui.userEdit); delete d->ui.userEdit; d->userEditCombo = new QComboBox(d->ui.credentialsGroup); d->userEditCombo->setEditable(true); d->ui.userEdit = d->userEditCombo->lineEdit(); d->ui.userNameLabel->setBuddy(d->userEditCombo); d->ui.formLayout->setWidget(row > -1 ? row : 0, userEditRole, d->userEditCombo); setTabOrder(d->ui.userEdit, d->ui.anonymousRadioButton); setTabOrder(d->ui.anonymousRadioButton, d->ui.domainEdit); setTabOrder(d->ui.domainEdit, d->ui.passEdit); setTabOrder(d->ui.passEdit, d->ui.keepCheckBox); connect(d->ui.userEdit, SIGNAL(returnPressed()), d->ui.passEdit, SLOT(setFocus())); } d->knownLogins = knownLogins; d->userEditCombo->addItems(knownLogins.keys()); d->userEditCombo->setFocus(); connect(d->userEditCombo, SIGNAL(activated(QString)), this, SLOT(activated(QString))); } void KPasswordDialog::KPasswordDialogPrivate::activated(const QString &userName) { QMap::ConstIterator it = knownLogins.constFind(userName); if (it != knownLogins.constEnd()) { q->setPassword(it.value()); } } void KPasswordDialog::accept() { if (!d->ui.errorMessage->isHidden()) { d->ui.errorMessage->setText(QString()); } // reset the font in case we had an error previously if (!d->ui.passwordLabel->isHidden()) { d->ui.passwordLabel->setFont(font()); d->ui.userNameLabel->setFont(font()); } // we do this to allow the error message, if any, to go away // checkPassword() may block for a period of time QTimer::singleShot(0, this, SLOT(actuallyAccept())); } void KPasswordDialog::KPasswordDialogPrivate::actuallyAccept() { if (!q->checkPassword()) { return; } bool keep = ui.keepCheckBox->isVisibleTo(q) && ui.keepCheckBox->isChecked(); emit q->gotPassword(q->password(), keep); if (ui.userEdit->isVisibleTo(q)) { emit q->gotUsernameAndPassword(q->username(), q->password(), keep); } q->QDialog::accept(); } bool KPasswordDialog::checkPassword() { return true; } QDialogButtonBox *KPasswordDialog::buttonBox() const { return d->ui.buttonBox; } #include "moc_kpassworddialog.cpp" diff --git a/src/kpassworddialog.h b/src/kpassworddialog.h index a5d7cfe..d4d179c 100644 --- a/src/kpassworddialog.h +++ b/src/kpassworddialog.h @@ -1,324 +1,322 @@ /* This file is part of the KDE libraries Copyright (C) 2000 David Faure Copyright (C) 2000 Dawit Alemayehu Copyright (C) 2007 Olivier Goffart This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KPASSWORDDIALOG_H #define KPASSWORDDIALOG_H #include #include #include #include /** * @class KPasswordDialog kpassworddialog.h KPasswordDialog * * A dialog for requesting a password and optionaly a login from the end user. * * \section usage Usage Example * * Requesting a simple password, assynchronous * * \code * KPasswordDialog *dlg = new KPasswordDialog( parent ); * dlg->setPrompt(i18n("Enter a password")); * connect( dlg, SIGNAL( gotPassword( const QString& , bool ) ) , this, SLOT( setPassword( const QString &) ) ); * connect( dlg, SIGNAL( rejected() ) , this, SLOT( slotCancel() ) ); * dlg->show(); * \endcode * * Requesting a login and a password, synchronous * * \code * KPasswordDialog dlg(parent, KPasswordDialog::ShowUsernameLine); * dlg.setPrompt(i18n("Enter a login and a password")); * if( !dlg.exec() ) * return; //the user canceled * use( dlg.username() , dlg.password() ); * \endcode * * \image html kpassworddialog.png "KPasswordDialog" * * @short dialog for requesting login and password from the end user */ class KWIDGETSADDONS_EXPORT KPasswordDialog : public QDialog { Q_OBJECT public: enum KPasswordDialogFlag { NoFlags = 0x00, /** * If this flag is set, the "keep this password" checkbox will been shown, * otherwise, it will not be shown and keepPassword will have no effect */ ShowKeepPassword = 0x01, /** * If this flag is set, there will be an additional line to let the user enter his login. * otherwise, only the password line will be shown. */ ShowUsernameLine = 0x02, /** * If this flag is set, the login lineedit will be in read only mode. */ UsernameReadOnly = 0x04, /** * If this flag is set, the Anonymous Login checkbox will be displayed * @since 4.1 */ ShowAnonymousLoginCheckBox = 0x08, /** * If this flag is set, there will be an additional line to let the user enter the domain. * @since 4.1 */ ShowDomainLine = 0x10, /** * If this flag is set, the domain lineedit will be in read only mode. * @since 4.1 */ DomainReadOnly = 0x20 }; Q_DECLARE_FLAGS(KPasswordDialogFlags, KPasswordDialogFlag) enum ErrorType { UnknownError = 0, /** * A problem with the user name as entered **/ UsernameError, /** * Incorrect password */ PasswordError, /** * Error preventing further attempts, will result in disabling most of the interface */ FatalError, /** * A problem with the domain as entered * @since 4.1 **/ DomainError }; /** * create a password dialog * * @param parent the parent widget * @param flags a set of KPasswordDialogFlag flags */ explicit KPasswordDialog(QWidget *parent = nullptr, const KPasswordDialogFlags &flags = KPasswordDialog::NoFlags); /** * Destructor */ ~KPasswordDialog(); /** * Sets the prompt to show to the user. * @param prompt instructional text to be shown. */ void setPrompt(const QString &prompt); /** * Returns the prompt */ QString prompt() const; /** * set an image that appears next to the prompt. */ void setPixmap(const QPixmap &); /** * */ QPixmap pixmap() const; /** * Adds a comment line to the dialog. * * This function allows you to add one additional comment * line to this widget. Calling this function after a * comment has already been added will not have any effect. * * @param label label for comment (ex:"Command:") * @param comment the actual comment text. */ void addCommentLine(const QString &label, const QString &comment); /** * Shows an error message in the dialog box. Prevents having to show a dialog-on-a-dialog. * * @param message the error message to show */ void showErrorMessage(const QString &message, const ErrorType type = PasswordError); /** * Returns the password entered by the user. * @return the password */ QString password() const; /** * set the default username. */ void setUsername(const QString &); /** * Returns the username entered by the user. * @return the user name */ QString username() const; /** * set the default domain. * @since 4.1 */ void setDomain(const QString &); /** * Returns the domain entered by the user. * @return the domain name * @since 4.1 */ QString domain() const; /** * set anonymous mode (all other fields will be grayed out) * @since 4.1 */ void setAnonymousMode(bool anonymous); /** * @return anonymous mode has been selected. * @since 4.1 */ bool anonymousMode() const; /** * Determines whether supplied authorization should * persist even after the application has been closed. * * this is set with the check password checkbox is the ShowKeepCheckBox flag * is set in the constructor, if it is not set, this function return false * * @return true to keep the password */ bool keepPassword() const; /** * Check or uncheck the "keep password" checkbox. * This can be used to check it before showing the dialog, to tell * the user that the password is stored already (e.g. in the wallet). * enableKeep must have been set to true in the constructor. * * has only effect if ShowKeepCheckBox is set in the constructor */ void setKeepPassword(bool b); /** * Sets the username field read-only and sets the * focus to the password field. * * this can also be set by passing UsernameReadOnly as flag in the constructor * * @param readOnly true to set the user field to read-only */ void setUsernameReadOnly(bool readOnly); /** * Presets the password. * If the password is not empty, the ability to show the password will not be available. * @param password the password to set */ void setPassword(const QString &password); /** * Presets a number of login+password pairs that the user can choose from. * The passwords can be empty if you simply want to offer usernames to choose from. * * This require the flag ShowUnernameLine to be set in the constructoe, and not the flag UsernameReadOnly * @param knownLogins map of known logins: the keys are usernames, the values are passwords. */ void setKnownLogins(const QMap &knownLogins); /** * @internal */ void accept() Q_DECL_OVERRIDE; /** * Returns the button box used in the dialog. * This can be used to add new buttons. * * @return the button box * * @since 5.0 */ QDialogButtonBox *buttonBox() const; Q_SIGNALS: /** * emitted when the dialog has been accepted * @param password the entered password * @param keep true if the "remember password" checkbox was checked, false otherwise. false if ShowKeepPassword was not set in the constructor */ void gotPassword(const QString &password, bool keep); /** * emitted when the dialog has been accepted, and ShowUsernameLine was set on the constructor * @param username the entered username * @param password the entered password * @param keep true if the "remember password" checkbox was checked, false otherwise. false if ShowKeepPassword was not set in the constructor */ void gotUsernameAndPassword(const QString &username, const QString &password, bool keep); protected: /** * Virtual function that can be overridden to provide password * checking in derived classes. It should return @p true if the * password is valid, @p false otherwise. */ virtual bool checkPassword(); private: Q_PRIVATE_SLOT(d, void actuallyAccept()) Q_PRIVATE_SLOT(d, void activated(const QString &userName)) Q_PRIVATE_SLOT(d, void updateFields()) - Q_PRIVATE_SLOT(d, void toggleEchoMode()) - Q_PRIVATE_SLOT(d, void showToggleEchoModeAction(const QString &text)) private: class KPasswordDialogPrivate; friend class KPasswordDialogPrivate; KPasswordDialogPrivate *const d; Q_DISABLE_COPY(KPasswordDialog) }; Q_DECLARE_OPERATORS_FOR_FLAGS(KPasswordDialog::KPasswordDialogFlags) #endif diff --git a/src/kpassworddialog.ui b/src/kpassworddialog.ui index 8c65270..b1ad99c 100644 --- a/src/kpassworddialog.ui +++ b/src/kpassworddialog.ui @@ -1,228 +1,239 @@ KPasswordDialog 0 0 - 400 - 227 + 412 + 328 10 0 Supply a username and password below. Qt::RichText Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft true Qt::Vertical QSizePolicy::Fixed 400 16 - No password, use anonymous (or guest) login + No password, use anonymous (or &guest) login Use this password: true - + + 1 + + + 1 + + + 1 + + 1 Username: true Domain: true Password: - - - QLineEdit::Password - + true Remember password QDialogButtonBox::Cancel|QDialogButtonBox::Ok KTitleWidget QWidget
ktitlewidget.h
+ + KPasswordLineEdit + QWidget +
kpasswordlineedit.h
+
anonymousRadioButton usePasswordButton userEdit domainEdit passEdit keepCheckBox buttonBox accepted() KPasswordDialog accept() 254 172 252 192 usePasswordButton toggled(bool) credentialsGroup setEnabled(bool) 77 92 50 216 buttonBox rejected() KPasswordDialog reject() 330 168 359 145 usePasswordButton clicked() credentialsGroup setFocus() 84 93 29 219
diff --git a/src/kpasswordlineedit.cpp b/src/kpasswordlineedit.cpp new file mode 100644 index 0000000..834cfb1 --- /dev/null +++ b/src/kpasswordlineedit.cpp @@ -0,0 +1,168 @@ +/* + Copyright (c) 2017 Montel Laurent + Copyright (C) 2015 Elvis Angelaccio + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2 of the License or + ( at your option ) version 3 or, at the discretion of KDE e.V. + ( which shall act as a proxy as in section 14 of the GPLv3 ), any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kpasswordlineedit.h" + +#include +#include +#include + + +class KPasswordLineEditPrivate +{ +public: + KPasswordLineEditPrivate(KPasswordLineEdit *qq) + : q(qq) + { + } + void initialize(); + void _k_echoModeToggled(); + void _k_showToggleEchoModeAction(const QString &text); + + QIcon passwordIcon; + QIcon visibleIcon; + + QLineEdit *passwordLineEdit = nullptr; + QAction *toggleEchoModeAction = nullptr; + bool isToggleEchoModeAvailable = true; + bool revealPasswordAvailable = true; + KPasswordLineEdit *q; +}; + +void KPasswordLineEditPrivate::initialize() +{ + QIcon visibilityIcon = QIcon::fromTheme(QStringLiteral("visibility"), QIcon(QStringLiteral(":/icons/visibility.svg"))); + toggleEchoModeAction = passwordLineEdit->addAction(visibilityIcon, QLineEdit::TrailingPosition); + toggleEchoModeAction->setObjectName(QStringLiteral("visibilityAction")); + toggleEchoModeAction->setVisible(false); + toggleEchoModeAction->setToolTip(QObject::tr("Change the visibility of the password")); + q->connect(toggleEchoModeAction, &QAction::triggered, q, [this]() {_k_echoModeToggled();}); + q->connect(passwordLineEdit, &QLineEdit::textChanged, q, [this](const QString &str) {_k_showToggleEchoModeAction(str);}); +} + +void KPasswordLineEditPrivate::_k_showToggleEchoModeAction(const QString &text) +{ + if (revealPasswordAvailable) { + toggleEchoModeAction->setVisible(isToggleEchoModeAvailable && (passwordLineEdit->echoMode() == QLineEdit::Normal || !text.isEmpty())); + } else { + toggleEchoModeAction->setVisible(false); + } +} + +void KPasswordLineEditPrivate::_k_echoModeToggled() +{ + if (passwordLineEdit->echoMode() == QLineEdit::Password) { + passwordLineEdit->setEchoMode(QLineEdit::Normal); + if (passwordIcon.isNull()) { + passwordIcon = QIcon::fromTheme(QStringLiteral("hint"), QIcon(QStringLiteral(":/icons/hint.svg"))); + } + toggleEchoModeAction->setIcon(passwordIcon); + } else if (passwordLineEdit->echoMode() == QLineEdit::Normal) { + if (visibleIcon.isNull()) { + visibleIcon = QIcon::fromTheme(QStringLiteral("visibility"), QIcon(QStringLiteral(":/icons/visibility.svg"))); + } + passwordLineEdit->setEchoMode(QLineEdit::Password); + toggleEchoModeAction->setIcon(visibleIcon); + } + Q_EMIT q->echoModeChanged(passwordLineEdit->echoMode()); +} + +KPasswordLineEdit::KPasswordLineEdit(QWidget *parent) + : QWidget(parent) + , d(new KPasswordLineEditPrivate(this)) +{ + QHBoxLayout *mainLayout = new QHBoxLayout(this); + mainLayout->setObjectName(QStringLiteral("mainlayout")); + mainLayout->setMargin(0); + d->passwordLineEdit = new QLineEdit(this); + d->passwordLineEdit->setObjectName(QStringLiteral("passwordlineedit")); + d->passwordLineEdit->setEchoMode(QLineEdit::Password); + connect(d->passwordLineEdit, &QLineEdit::textChanged, this, &KPasswordLineEdit::passwordChanged); + mainLayout->addWidget(d->passwordLineEdit); + d->initialize(); +} + +KPasswordLineEdit::~KPasswordLineEdit() +{ + delete d; +} + +void KPasswordLineEdit::setPassword(const QString &password) +{ + if (d->passwordLineEdit->text() != password) { + d->isToggleEchoModeAvailable = password.isEmpty(); + d->passwordLineEdit->setText(password); + Q_EMIT passwordChanged(password); + } +} + +QString KPasswordLineEdit::password() const +{ + return d->passwordLineEdit->text(); +} + +void KPasswordLineEdit::clear() +{ + d->passwordLineEdit->clear(); +} + +void KPasswordLineEdit::setClearButtonEnabled(bool clear) +{ + d->passwordLineEdit->setClearButtonEnabled(clear); +} + +bool KPasswordLineEdit::isClearButtonEnabled() const +{ + return d->passwordLineEdit->isClearButtonEnabled(); +} + +void KPasswordLineEdit::setEchoMode(QLineEdit::EchoMode mode) +{ + d->passwordLineEdit->setEchoMode(mode); +} + +QLineEdit::EchoMode KPasswordLineEdit::echoMode() const +{ + return d->passwordLineEdit->echoMode(); +} + +QLineEdit *KPasswordLineEdit::lineEdit() const +{ + return d->passwordLineEdit; +} + +void KPasswordLineEdit::setRevealPasswordAvailable(bool reveal) +{ + d->revealPasswordAvailable = reveal; + d->_k_showToggleEchoModeAction(password()); +} + +bool KPasswordLineEdit::isRevealPasswordAvailable() const +{ + return d->revealPasswordAvailable; +} + +QAction *KPasswordLineEdit::toggleEchoModeAction() const +{ + return d->toggleEchoModeAction; +} + +#include "moc_kpasswordlineedit.cpp" diff --git a/src/kpasswordlineedit.h b/src/kpasswordlineedit.h new file mode 100644 index 0000000..7c7817a --- /dev/null +++ b/src/kpasswordlineedit.h @@ -0,0 +1,139 @@ +/* + Copyright (c) 2017 Montel Laurent + Copyright (C) 2015 Elvis Angelaccio + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2 of the License or + ( at your option ) version 3 or, at the discretion of KDE e.V. + ( which shall act as a proxy as in section 14 of the GPLv3 ), any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KPASSWORDLINEEDIT_H +#define KPASSWORDLINEEDIT_H + +#include +#include +#include +class QAction; +class KPasswordLineEditPrivate; + +/** + * @class KPasswordLineEdit kpasswordlineedit.h KPasswordLineEdit + * + * A lineedit which allows to display password + * + * \section usage Usage Example + * + * Get password + * + * \code + * KPasswordLineEdit *passwordLineEdit = new KPasswordLineEdit(parent); + * QString password = passwordLineEdit->password(); + * \endcode + * + * @author Laurent Montel + * @since 5.37 + */ + +class KWIDGETSADDONS_EXPORT KPasswordLineEdit : public QWidget +{ + Q_OBJECT + Q_PROPERTY(QString password READ password WRITE setPassword NOTIFY passwordChanged) + Q_PROPERTY(bool clearButtonEnabled READ isClearButtonEnabled WRITE setClearButtonEnabled) + Q_PROPERTY(QLineEdit::EchoMode echoMode READ echoMode WRITE setEchoMode NOTIFY echoModeChanged) +public: + /** + * Constructs a lineedit password widget. + * @since 5.37 + * + * @param parent Passed to lower level constructor. + */ + explicit KPasswordLineEdit(QWidget *parent = nullptr); + /** + * Destructs the lineedit password widget. + */ + ~KPasswordLineEdit(); + + /** + * Assign password + */ + void setPassword(const QString &password); + + /** + * Returns the password entered. + */ + QString password() const; + + /** + * Clear text + */ + void clear(); + + /** + * Show/hide clear button (false by default) + */ + void setClearButtonEnabled(bool clear); + + /** + * Inform if we show or not clear button + */ + bool isClearButtonEnabled() const; + + /** + * Change echo mode (QLineEdit::Password by default) + */ + void setEchoMode(QLineEdit::EchoMode mode); + + /** + * Return echo mode + */ + QLineEdit::EchoMode echoMode() const; + + /** + * Whether to show the visibility trailing action in the line edit. + * Default is true. This can be used to honor the lineedit_reveal_password + * kiosk key, for example: + * \code + * passwordLineEdit.setRevealPasswordAvailable(KAuthorized::authorize(QStringLiteral("lineedit_reveal_password"))); + * \endcode + */ + void setRevealPasswordAvailable(bool reveal); + + /** + * Whether the visibility trailing action in the line edit is visible. + */ + bool isRevealPasswordAvailable() const; + + /** + * Returns the QAction (@internal) + */ + QAction *toggleEchoModeAction() const; + + /** + * Returns the lineedit widget. + */ + QLineEdit *lineEdit() const; + +Q_SIGNALS: + /** + * When we click on visibility icon echo mode is switched between Normal echo mode and Password echo mode + */ + void echoModeChanged(QLineEdit::EchoMode echoMode); + void passwordChanged(const QString &password); + +private: + KPasswordLineEditPrivate *const d; +}; + +#endif diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 0435a90..9975049 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,56 +1,57 @@ include(ECMMarkAsTest) find_package(Qt5 ${REQUIRED_QT_VERSION} CONFIG REQUIRED Test) macro(kwidgetsaddons_executable_tests) foreach(_testname ${ARGN}) add_executable(${_testname} ${_testname}.cpp) target_link_libraries(${_testname} Qt5::Test KF5::WidgetsAddons) ecm_mark_as_test(${_testname}) endforeach(_testname) endmacro() kwidgetsaddons_executable_tests( kanimatedbuttontest kcharselecttest kcollapsiblegroupboxtest kdatepicktest kdatetimeedittestapp kledtest kmessageboxtest kmessageboxwidtest kselectactiontest kseparatortest ksqueezedtextlabeltest ktitlewidgettest kfontrequestertest kpassworddialogtest keditlistwidgettest kratingwidgettest kactionselectortest kcolorcombotest kpixmapregionselectordialogtest ktoolbarlabelactiontest kpagedialogtest kpagewidgettest kassistantdialogtest kmessagewidgettest knewpassworddialogtest knewpasswordwidget_test kpixmapsequenceoverlaypaintertest kmimetypechoosertest ksplittercollapserbuttongui_test ktooltipwidget_test + kpasswordlineedit_test ) add_executable(kdatetabletest kdatetabletest.cpp ../src/kdatetable.cpp) target_include_directories(kdatetabletest PRIVATE ../src) target_link_libraries(kdatetabletest Qt5::Widgets) ecm_mark_as_test(kdatetabletest) set(kcolumnresizertestapp_SRCS kcolumnresizertestapp.cpp) qt5_wrap_ui(kcolumnresizertestapp_SRCS kcolumnresizertestapp.ui) add_executable(kcolumnresizertestapp ${kcolumnresizertestapp_SRCS}) target_link_libraries(kcolumnresizertestapp KF5::WidgetsAddons Qt5::Widgets) ecm_mark_as_test(kcolumnresizertestapp) diff --git a/tests/kpasswordlineedit_test.cpp b/tests/kpasswordlineedit_test.cpp new file mode 100644 index 0000000..034040b --- /dev/null +++ b/tests/kpasswordlineedit_test.cpp @@ -0,0 +1,49 @@ +/* + Copyright (c) 2017 Montel Laurent + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2 of the License or + ( at your option ) version 3 or, at the discretion of KDE e.V. + ( which shall act as a proxy as in section 14 of the GPLv3 ), any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include +#include + +#include +#include + +#include + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + QCommandLineParser parser; + parser.addVersionOption(); + parser.addHelpOption(); + parser.process(app); + + QWidget *w = new QWidget; + QVBoxLayout *vbox = new QVBoxLayout(w); + + KPasswordLineEdit *passwordLineEdit = new KPasswordLineEdit(w); + vbox->addWidget(passwordLineEdit); + vbox->addStretch(); + + w->resize(400, 400); + w->show(); + + return app.exec(); +} +