diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2dca9e606a..fd823955db 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -123,6 +123,7 @@ set(keepassx_SOURCES gui/UnlockDatabaseWidget.cpp gui/UnlockDatabaseDialog.cpp gui/WelcomeWidget.cpp + gui/widgets/ElidedLabel.cpp gui/csvImport/CsvImportWidget.cpp gui/csvImport/CsvImportWizard.cpp gui/csvImport/CsvParserModel.cpp diff --git a/src/gui/DetailsWidget.cpp b/src/gui/DetailsWidget.cpp index 98c9e1ecb4..6dbe1148ef 100644 --- a/src/gui/DetailsWidget.cpp +++ b/src/gui/DetailsWidget.cpp @@ -34,7 +34,6 @@ namespace { constexpr int GeneralTabIndex = 0; -const QString hierarchySeparator(" / "); } DetailsWidget::DetailsWidget(QWidget* parent) @@ -169,25 +168,25 @@ void DetailsWidget::updateEntryGeneralTab() if (!config()->get("security/hidepassworddetails").toBool()) { const QString password = m_currentEntry->resolveMultiplePlaceholders(m_currentEntry->password()); - m_ui->entryPasswordLabel->setText(shortPassword(password)); + m_ui->entryPasswordLabel->setRawText(password); m_ui->entryPasswordLabel->setToolTip(password); } else { - m_ui->entryPasswordLabel->setText("****"); + m_ui->entryPasswordLabel->setRawText("****"); + m_ui->entryPasswordLabel->setToolTip(QString()); } - QString url = m_currentEntry->webUrl(); + const QString url = m_currentEntry->webUrl(); if (!url.isEmpty()) { // URL is well formed and can be opened in a browser // create a new display url that masks password placeholders // the actual link will use the password - url = QString("%2").arg(url).arg(shortUrl(m_currentEntry->displayUrl())); - m_ui->entryUrlLabel->setOpenExternalLinks(true); + m_ui->entryUrlLabel->setRawText(m_currentEntry->displayUrl()); + m_ui->entryUrlLabel->setUrl(url); } else { // Fallback to the raw url string - url = shortUrl(m_currentEntry->resolveMultiplePlaceholders(m_currentEntry->url())); - m_ui->entryUrlLabel->setOpenExternalLinks(false); + m_ui->entryUrlLabel->setRawText(m_currentEntry->resolveMultiplePlaceholders(m_currentEntry->url())); + m_ui->entryUrlLabel->setUrl(QString()); } - m_ui->entryUrlLabel->setText(url); const TimeInfo entryTime = m_currentEntry->timeInfo(); const QString expires = entryTime.expires() ? entryTime.expiryTime().toString(Qt::DefaultLocaleShortDate) @@ -313,33 +312,11 @@ QPixmap DetailsWidget::preparePixmap(const QPixmap& pixmap, int size) return pixmap; } - -QString DetailsWidget::shortUrl(const QString& url) -{ - // TODO: create elided text - QString newurl = ""; - if (url.length() > 60) { - newurl.append(url.left(20)); - newurl.append("…"); - newurl.append(url.right(20)); - return newurl; - } - return url; -} - -QString DetailsWidget::shortPassword(const QString& password) -{ - // TODO: create elided text - if (password.length() > 60) { - return QString("%1…").arg(password.left(60)); - } - return password; -} - QString DetailsWidget::hierarchy(const Group* group, const QString& title) { + const QString separator(" / "); QStringList hierarchy = group->hierarchy(); hierarchy.removeFirst(); hierarchy.append(title); - return QString("%1%2").arg(hierarchySeparator, hierarchy.join(hierarchySeparator)); + return QString("%1%2").arg(separator, hierarchy.join(separator)); } diff --git a/src/gui/DetailsWidget.h b/src/gui/DetailsWidget.h index 7bea2e6310..5b5d698336 100644 --- a/src/gui/DetailsWidget.h +++ b/src/gui/DetailsWidget.h @@ -18,9 +18,10 @@ #ifndef KEEPASSX_DETAILSWIDGET_H #define KEEPASSX_DETAILSWIDGET_H -#include "gui/DatabaseWidget.h" #include +#include "gui/DatabaseWidget.h" + namespace Ui { class DetailsWidget; } @@ -57,13 +58,12 @@ private slots: void updateTotp(); void updateTabIndexes(); - private: void setTabEnabled(QTabWidget *tabWidget, QWidget* widget, bool enabled); + static QPixmap preparePixmap(const QPixmap& pixmap, int size); - static QString shortUrl(const QString& url); - static QString shortPassword(const QString& password); - static QString hierarchy(const Group *group, const QString &title); + static QString hierarchy(const Group* group, const QString& title); + const QScopedPointer m_ui; bool m_locked; Entry* m_currentEntry; diff --git a/src/gui/DetailsWidget.ui b/src/gui/DetailsWidget.ui index 88c84ad431..5446f65106 100644 --- a/src/gui/DetailsWidget.ui +++ b/src/gui/DetailsWidget.ui @@ -152,7 +152,7 @@ - + @@ -196,6 +196,12 @@ + + + 100 + 0 + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse @@ -224,7 +230,14 @@ - + + + + 100 + 0 + + + @@ -249,12 +262,12 @@ - - - - 0 - 0 - + + + + 100 + 0 + PointingHandCursor @@ -297,7 +310,7 @@ 20 - 40 + 10 @@ -530,14 +543,7 @@ - - - - 0 - 0 - - - + @@ -562,14 +568,7 @@ - - - - 0 - 0 - - - + @@ -594,14 +593,7 @@ - - - - 0 - 0 - - - + @@ -611,7 +603,7 @@ 20 - 40 + 10 @@ -663,6 +655,11 @@
gui/entry/EntryAttachmentsWidget.h
1 + + ElidedLabel + QLabel +
gui/widgets/ElidedLabel.h
+
diff --git a/src/gui/widgets/ElidedLabel.cpp b/src/gui/widgets/ElidedLabel.cpp new file mode 100644 index 0000000000..1642bdec8b --- /dev/null +++ b/src/gui/widgets/ElidedLabel.cpp @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2017 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "ElidedLabel.h" + +#include +#include + +namespace { +const QString htmlLinkTemplate("%2"); +} + +ElidedLabel::ElidedLabel(QWidget* parent, Qt::WindowFlags f) + : QLabel(parent, f) + , m_elideMode(Qt::ElideMiddle) +{ + connect(this, SIGNAL(elideModeChanged(Qt::TextElideMode)), this, SLOT(updateElidedText())); + connect(this, SIGNAL(rawTextChanged(QString)), this, SLOT(updateElidedText())); + connect(this, SIGNAL(urlChanged(QString)), this, SLOT(updateElidedText())); +} + +ElidedLabel::ElidedLabel(const QString& text, QWidget* parent, Qt::WindowFlags f) + : ElidedLabel(parent, f) +{ + setText(text); +} + +Qt::TextElideMode ElidedLabel::elideMode() const +{ + return m_elideMode; +} + +QString ElidedLabel::rawText() const +{ + return m_rawText; +} + +QString ElidedLabel::url() const +{ + return m_url; +} + +void ElidedLabel::setElideMode(Qt::TextElideMode elideMode) +{ + if (m_elideMode == elideMode) + return; + + if (m_elideMode != Qt::ElideNone) { + setWordWrap(false); + } + + m_elideMode = elideMode; + emit elideModeChanged(m_elideMode); +} + +void ElidedLabel::setRawText(const QString& elidedText) +{ + if (m_rawText == elidedText) + return; + + m_rawText = elidedText; + emit rawTextChanged(m_rawText); +} + +void ElidedLabel::setUrl(const QString& url) +{ + if (m_url == url) + return; + + m_url = url; + emit urlChanged(m_url); +} + +void ElidedLabel::clear() +{ + setRawText(QString()); + setElideMode(Qt::ElideMiddle); + setUrl(QString()); + QLabel::clear(); +} + +void ElidedLabel::updateElidedText() +{ + if (m_rawText.isEmpty()) { + QLabel::clear(); + return; + } + + QString displayText = m_rawText; + if (m_elideMode != Qt::ElideNone) { + const QFontMetrics metrix(font()); + displayText = metrix.elidedText(m_rawText, m_elideMode, width() - 2); + } + setText(m_url.isEmpty() ? displayText : htmlLinkTemplate.arg(m_url, displayText)); + setOpenExternalLinks(!m_url.isEmpty()); +} + +void ElidedLabel::resizeEvent(QResizeEvent* event) +{ + updateElidedText(); + QLabel::resizeEvent(event); +} diff --git a/src/gui/widgets/ElidedLabel.h b/src/gui/widgets/ElidedLabel.h new file mode 100644 index 0000000000..c7694b5a10 --- /dev/null +++ b/src/gui/widgets/ElidedLabel.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2017 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef KEEPASSX_ELIDEDLABEL_H +#define KEEPASSX_ELIDEDLABEL_H + +#include + +class QResizeEvent; + +class ElidedLabel : public QLabel +{ + Q_OBJECT + Q_PROPERTY(Qt::TextElideMode elideMode READ elideMode WRITE setElideMode NOTIFY elideModeChanged) + Q_PROPERTY(QString rawText READ rawText WRITE setRawText NOTIFY rawTextChanged) + Q_PROPERTY(QString url READ url WRITE setUrl NOTIFY urlChanged) +public: + explicit ElidedLabel(QWidget *parent=nullptr, Qt::WindowFlags f=Qt::WindowFlags()); + explicit ElidedLabel(const QString &text, QWidget *parent=nullptr, Qt::WindowFlags f=Qt::WindowFlags()); + + Qt::TextElideMode elideMode() const; + QString rawText() const; + QString url() const; + +public slots: + void setElideMode(Qt::TextElideMode elideMode); + void setRawText(const QString& rawText); + void setUrl(const QString& url); + void clear(); + +signals: + void elideModeChanged(Qt::TextElideMode elideMode); + void rawTextChanged(QString rawText); + void urlChanged(QString url); + +private slots: + void updateElidedText(); + +private: + void resizeEvent(QResizeEvent* event); + + Qt::TextElideMode m_elideMode; + QString m_rawText; + QString m_url; +}; + +#endif // KEEPASSX_ELIDEDLABEL_H