mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2025-02-04 08:55:31 -05:00
Merge remote-tracking branch 'upstream/develop' into feature/import-csv-format
This commit is contained in:
commit
705b74b3ba
@ -1,6 +1,7 @@
|
|||||||
# KeePassXC - KeePass Cross-platform Community Edition
|
# KeePassXC - KeePass Cross-platform Community Edition
|
||||||
|
|
||||||
[![Travis Build Status](https://travis-ci.org/keepassxreboot/keepassxc.svg?branch=develop)](https://travis-ci.org/keepassxreboot/keepassxc) [![Coverage Status](https://coveralls.io/repos/github/keepassxreboot/keepassxc/badge.svg)](https://coveralls.io/github/keepassxreboot/keepassxc)
|
[![Travis Build Status](https://travis-ci.org/keepassxreboot/keepassxc.svg?branch=develop)](https://travis-ci.org/keepassxreboot/keepassxc) [![Coverage Status](https://coveralls.io/repos/github/keepassxreboot/keepassxc/badge.svg)](https://coveralls.io/github/keepassxreboot/keepassxc)
|
||||||
|
<a href='https://pledgie.com/campaigns/33487'><img alt='KeePassXC Authenticode Certificate Campaign!' align=right src='https://pledgie.com/campaigns/33487.png?skin_name=chrome' border='0'></a>
|
||||||
|
|
||||||
## About
|
## About
|
||||||
KeePassXC is a community fork of [KeePassX](https://www.keepassx.org/) with the goal to extend and improve it with new features and bugfixes to provide a feature-rich, fully cross-platform and modern open-source password manager.
|
KeePassXC is a community fork of [KeePassX](https://www.keepassx.org/) with the goal to extend and improve it with new features and bugfixes to provide a feature-rich, fully cross-platform and modern open-source password manager.
|
||||||
|
@ -254,6 +254,17 @@ bool Entry::isExpired() const
|
|||||||
return m_data.timeInfo.expires() && m_data.timeInfo.expiryTime() < QDateTime::currentDateTimeUtc();
|
return m_data.timeInfo.expires() && m_data.timeInfo.expiryTime() < QDateTime::currentDateTimeUtc();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Entry::hasReferences() const
|
||||||
|
{
|
||||||
|
const QList<QString> keyList = EntryAttributes::DefaultAttributes;
|
||||||
|
for (const QString& key : keyList) {
|
||||||
|
if (m_attributes->isReference(key)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
EntryAttributes* Entry::attributes()
|
EntryAttributes* Entry::attributes()
|
||||||
{
|
{
|
||||||
return m_attributes;
|
return m_attributes;
|
||||||
@ -679,20 +690,20 @@ QString Entry::resolvePlaceholder(const QString& str) const
|
|||||||
// using format from http://keepass.info/help/base/fieldrefs.html at the time of writing,
|
// using format from http://keepass.info/help/base/fieldrefs.html at the time of writing,
|
||||||
// but supporting lookups of standard fields and references by UUID only
|
// but supporting lookups of standard fields and references by UUID only
|
||||||
|
|
||||||
QRegExp tmpRegExp("\\{REF:([TUPAN])@I:([^}]+)\\}", Qt::CaseInsensitive, QRegExp::RegExp2);
|
QRegExp* tmpRegExp = m_attributes->referenceRegExp();
|
||||||
if (tmpRegExp.indexIn(result) != -1) {
|
if (tmpRegExp->indexIn(result) != -1) {
|
||||||
// cap(0) contains the whole reference
|
// cap(0) contains the whole reference
|
||||||
// cap(1) contains which field is wanted
|
// cap(1) contains which field is wanted
|
||||||
// cap(2) contains the uuid of the referenced entry
|
// cap(2) contains the uuid of the referenced entry
|
||||||
Entry* tmpRefEntry = m_group->database()->resolveEntry(Uuid(QByteArray::fromHex(tmpRegExp.cap(2).toLatin1())));
|
Entry* tmpRefEntry = m_group->database()->resolveEntry(Uuid(QByteArray::fromHex(tmpRegExp->cap(2).toLatin1())));
|
||||||
if (tmpRefEntry) {
|
if (tmpRefEntry) {
|
||||||
// entry found, get the relevant field
|
// entry found, get the relevant field
|
||||||
QString tmpRefField = tmpRegExp.cap(1).toLower();
|
QString tmpRefField = tmpRegExp->cap(1).toLower();
|
||||||
if (tmpRefField == "t") result.replace(tmpRegExp.cap(0), tmpRefEntry->title(), Qt::CaseInsensitive);
|
if (tmpRefField == "t") result.replace(tmpRegExp->cap(0), tmpRefEntry->title(), Qt::CaseInsensitive);
|
||||||
else if (tmpRefField == "u") result.replace(tmpRegExp.cap(0), tmpRefEntry->username(), Qt::CaseInsensitive);
|
else if (tmpRefField == "u") result.replace(tmpRegExp->cap(0), tmpRefEntry->username(), Qt::CaseInsensitive);
|
||||||
else if (tmpRefField == "p") result.replace(tmpRegExp.cap(0), tmpRefEntry->password(), Qt::CaseInsensitive);
|
else if (tmpRefField == "p") result.replace(tmpRegExp->cap(0), tmpRefEntry->password(), Qt::CaseInsensitive);
|
||||||
else if (tmpRefField == "a") result.replace(tmpRegExp.cap(0), tmpRefEntry->url(), Qt::CaseInsensitive);
|
else if (tmpRefField == "a") result.replace(tmpRegExp->cap(0), tmpRefEntry->url(), Qt::CaseInsensitive);
|
||||||
else if (tmpRefField == "n") result.replace(tmpRegExp.cap(0), tmpRefEntry->notes(), Qt::CaseInsensitive);
|
else if (tmpRefField == "n") result.replace(tmpRegExp->cap(0), tmpRefEntry->notes(), Qt::CaseInsensitive);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,6 +79,7 @@ public:
|
|||||||
QString password() const;
|
QString password() const;
|
||||||
QString notes() const;
|
QString notes() const;
|
||||||
bool isExpired() const;
|
bool isExpired() const;
|
||||||
|
bool hasReferences() const;
|
||||||
EntryAttributes* attributes();
|
EntryAttributes* attributes();
|
||||||
const EntryAttributes* attributes() const;
|
const EntryAttributes* attributes() const;
|
||||||
EntryAttachments* attachments();
|
EntryAttachments* attachments();
|
||||||
|
@ -28,6 +28,7 @@ const QString EntryAttributes::RememberCmdExecAttr = "_EXEC_CMD";
|
|||||||
|
|
||||||
EntryAttributes::EntryAttributes(QObject* parent)
|
EntryAttributes::EntryAttributes(QObject* parent)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
|
, m_referenceRegExp("\\{REF:([TUPAN])@I:([^}]+)\\}", Qt::CaseInsensitive, QRegExp::RegExp2)
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
@ -69,6 +70,25 @@ bool EntryAttributes::isProtected(const QString& key) const
|
|||||||
return m_protectedAttributes.contains(key);
|
return m_protectedAttributes.contains(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool EntryAttributes::isReference(const QString& key) const
|
||||||
|
{
|
||||||
|
if (!m_attributes.contains(key)) {
|
||||||
|
Q_ASSERT(false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString data = value(key);
|
||||||
|
if (m_referenceRegExp.indexIn(data) != -1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QRegExp* EntryAttributes::referenceRegExp()
|
||||||
|
{
|
||||||
|
return &m_referenceRegExp;
|
||||||
|
}
|
||||||
|
|
||||||
void EntryAttributes::set(const QString& key, const QString& value, bool protect)
|
void EntryAttributes::set(const QString& key, const QString& value, bool protect)
|
||||||
{
|
{
|
||||||
bool emitModified = false;
|
bool emitModified = false;
|
||||||
|
@ -35,6 +35,8 @@ public:
|
|||||||
QString value(const QString& key) const;
|
QString value(const QString& key) const;
|
||||||
bool contains(const QString& key) const;
|
bool contains(const QString& key) const;
|
||||||
bool isProtected(const QString& key) const;
|
bool isProtected(const QString& key) const;
|
||||||
|
bool isReference(const QString& key) const;
|
||||||
|
QRegExp* referenceRegExp();
|
||||||
void set(const QString& key, const QString& value, bool protect = false);
|
void set(const QString& key, const QString& value, bool protect = false);
|
||||||
void remove(const QString& key);
|
void remove(const QString& key);
|
||||||
void rename(const QString& oldKey, const QString& newKey);
|
void rename(const QString& oldKey, const QString& newKey);
|
||||||
@ -71,6 +73,7 @@ Q_SIGNALS:
|
|||||||
private:
|
private:
|
||||||
QMap<QString, QString> m_attributes;
|
QMap<QString, QString> m_attributes;
|
||||||
QSet<QString> m_protectedAttributes;
|
QSet<QString> m_protectedAttributes;
|
||||||
|
QRegExp m_referenceRegExp;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // KEEPASSX_ENTRYATTRIBUTES_H
|
#endif // KEEPASSX_ENTRYATTRIBUTES_H
|
||||||
|
@ -132,6 +132,8 @@ void EditEntryWidget::setupAdvanced()
|
|||||||
connect(m_advancedUi->addAttributeButton, SIGNAL(clicked()), SLOT(insertAttribute()));
|
connect(m_advancedUi->addAttributeButton, SIGNAL(clicked()), SLOT(insertAttribute()));
|
||||||
connect(m_advancedUi->editAttributeButton, SIGNAL(clicked()), SLOT(editCurrentAttribute()));
|
connect(m_advancedUi->editAttributeButton, SIGNAL(clicked()), SLOT(editCurrentAttribute()));
|
||||||
connect(m_advancedUi->removeAttributeButton, SIGNAL(clicked()), SLOT(removeCurrentAttribute()));
|
connect(m_advancedUi->removeAttributeButton, SIGNAL(clicked()), SLOT(removeCurrentAttribute()));
|
||||||
|
connect(m_advancedUi->protectAttributeButton, SIGNAL(toggled(bool)), SLOT(protectCurrentAttribute(bool)));
|
||||||
|
connect(m_advancedUi->revealAttributeButton, SIGNAL(clicked(bool)), SLOT(revealCurrentAttribute()));
|
||||||
connect(m_advancedUi->attributesView->selectionModel(),
|
connect(m_advancedUi->attributesView->selectionModel(),
|
||||||
SIGNAL(currentChanged(QModelIndex,QModelIndex)),
|
SIGNAL(currentChanged(QModelIndex,QModelIndex)),
|
||||||
SLOT(updateCurrentAttribute()));
|
SLOT(updateCurrentAttribute()));
|
||||||
@ -351,6 +353,11 @@ void EditEntryWidget::setForms(const Entry* entry, bool restore)
|
|||||||
m_advancedUi->attributesEdit->setEnabled(false);
|
m_advancedUi->attributesEdit->setEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QList<int> sizes = m_advancedUi->attributesSplitter->sizes();
|
||||||
|
sizes.replace(0, m_advancedUi->attributesSplitter->width() * 0.3);
|
||||||
|
sizes.replace(1, m_advancedUi->attributesSplitter->width() * 0.7);
|
||||||
|
m_advancedUi->attributesSplitter->setSizes(sizes);
|
||||||
|
|
||||||
IconStruct iconStruct;
|
IconStruct iconStruct;
|
||||||
iconStruct.uuid = entry->iconUuid();
|
iconStruct.uuid = entry->iconUuid();
|
||||||
iconStruct.number = entry->iconNumber();
|
iconStruct.number = entry->iconNumber();
|
||||||
@ -409,7 +416,7 @@ void EditEntryWidget::saveEntry()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_advancedUi->attributesView->currentIndex().isValid()) {
|
if (m_advancedUi->attributesView->currentIndex().isValid() && m_advancedUi->attributesEdit->isEnabled()) {
|
||||||
QString key = m_attributesModel->keyByIndex(m_advancedUi->attributesView->currentIndex());
|
QString key = m_attributesModel->keyByIndex(m_advancedUi->attributesView->currentIndex());
|
||||||
m_entryAttributes->set(key, m_advancedUi->attributesEdit->toPlainText(),
|
m_entryAttributes->set(key, m_advancedUi->attributesEdit->toPlainText(),
|
||||||
m_entryAttributes->isProtected(key));
|
m_entryAttributes->isProtected(key));
|
||||||
@ -578,46 +585,96 @@ void EditEntryWidget::removeCurrentAttribute()
|
|||||||
QModelIndex index = m_advancedUi->attributesView->currentIndex();
|
QModelIndex index = m_advancedUi->attributesView->currentIndex();
|
||||||
|
|
||||||
if (index.isValid()) {
|
if (index.isValid()) {
|
||||||
m_entryAttributes->remove(m_attributesModel->keyByIndex(index));
|
if (MessageBox::question(this, tr("Confirm Remove"), tr("Are you sure you want to remove this attribute?"),
|
||||||
|
QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
|
||||||
|
m_entryAttributes->remove(m_attributesModel->keyByIndex(index));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditEntryWidget::updateCurrentAttribute()
|
void EditEntryWidget::updateCurrentAttribute()
|
||||||
{
|
{
|
||||||
QModelIndex newIndex = m_advancedUi->attributesView->currentIndex();
|
QModelIndex newIndex = m_advancedUi->attributesView->currentIndex();
|
||||||
|
QString newKey = m_attributesModel->keyByIndex(newIndex);
|
||||||
|
|
||||||
if (m_history) {
|
if (!m_history && m_currentAttribute != newIndex) {
|
||||||
if (newIndex.isValid()) {
|
// Save changes to the currently selected attribute if editing is enabled
|
||||||
QString key = m_attributesModel->keyByIndex(newIndex);
|
if (m_currentAttribute.isValid() && m_advancedUi->attributesEdit->isEnabled()) {
|
||||||
m_advancedUi->attributesEdit->setPlainText(m_entryAttributes->value(key));
|
QString currKey = m_attributesModel->keyByIndex(m_currentAttribute);
|
||||||
m_advancedUi->attributesEdit->setEnabled(true);
|
m_entryAttributes->set(currKey, m_advancedUi->attributesEdit->toPlainText(),
|
||||||
|
m_entryAttributes->isProtected(currKey));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
displayAttribute(newIndex, m_entryAttributes->isProtected(newKey));
|
||||||
|
|
||||||
|
m_currentAttribute = newIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditEntryWidget::displayAttribute(QModelIndex index, bool showProtected)
|
||||||
|
{
|
||||||
|
// Block signals to prevent extra calls
|
||||||
|
m_advancedUi->protectAttributeButton->blockSignals(true);
|
||||||
|
|
||||||
|
if (index.isValid()) {
|
||||||
|
QString key = m_attributesModel->keyByIndex(index);
|
||||||
|
if (showProtected) {
|
||||||
|
m_advancedUi->attributesEdit->setPlainText(tr("[PROTECTED] Press reveal to view or edit"));
|
||||||
|
m_advancedUi->attributesEdit->setEnabled(false);
|
||||||
|
m_advancedUi->revealAttributeButton->setEnabled(true);
|
||||||
|
m_advancedUi->protectAttributeButton->setChecked(true);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
m_advancedUi->attributesEdit->setPlainText("");
|
m_advancedUi->attributesEdit->setPlainText(m_entryAttributes->value(key));
|
||||||
m_advancedUi->attributesEdit->setEnabled(false);
|
m_advancedUi->attributesEdit->setEnabled(true);
|
||||||
|
m_advancedUi->revealAttributeButton->setEnabled(false);
|
||||||
|
m_advancedUi->protectAttributeButton->setChecked(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Don't allow editing in history view
|
||||||
|
m_advancedUi->protectAttributeButton->setEnabled(!m_history);
|
||||||
|
m_advancedUi->editAttributeButton->setEnabled(!m_history);
|
||||||
|
m_advancedUi->removeAttributeButton->setEnabled(!m_history);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (m_currentAttribute != newIndex) {
|
m_advancedUi->attributesEdit->setPlainText("");
|
||||||
if (m_currentAttribute.isValid()) {
|
m_advancedUi->attributesEdit->setEnabled(false);
|
||||||
QString key = m_attributesModel->keyByIndex(m_currentAttribute);
|
m_advancedUi->revealAttributeButton->setEnabled(false);
|
||||||
m_entryAttributes->set(key, m_advancedUi->attributesEdit->toPlainText(),
|
m_advancedUi->protectAttributeButton->setChecked(false);
|
||||||
m_entryAttributes->isProtected(key));
|
m_advancedUi->protectAttributeButton->setEnabled(false);
|
||||||
}
|
m_advancedUi->editAttributeButton->setEnabled(false);
|
||||||
|
m_advancedUi->removeAttributeButton->setEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
if (newIndex.isValid()) {
|
m_advancedUi->protectAttributeButton->blockSignals(false);
|
||||||
QString key = m_attributesModel->keyByIndex(newIndex);
|
}
|
||||||
m_advancedUi->attributesEdit->setPlainText(m_entryAttributes->value(key));
|
|
||||||
m_advancedUi->attributesEdit->setEnabled(true);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
m_advancedUi->attributesEdit->setPlainText("");
|
|
||||||
m_advancedUi->attributesEdit->setEnabled(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_advancedUi->editAttributeButton->setEnabled(newIndex.isValid());
|
void EditEntryWidget::protectCurrentAttribute(bool state)
|
||||||
m_advancedUi->removeAttributeButton->setEnabled(newIndex.isValid());
|
{
|
||||||
m_currentAttribute = newIndex;
|
QModelIndex index = m_advancedUi->attributesView->currentIndex();
|
||||||
|
if (!m_history && index.isValid()) {
|
||||||
|
QString key = m_attributesModel->keyByIndex(index);
|
||||||
|
if (state) {
|
||||||
|
// Save the current text and protect the attribute
|
||||||
|
m_entryAttributes->set(key, m_advancedUi->attributesEdit->toPlainText(), true);
|
||||||
|
} else {
|
||||||
|
// Unprotect the current attribute value (don't save text as it is obscured)
|
||||||
|
m_entryAttributes->set(key, m_entryAttributes->value(key), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display the attribute
|
||||||
|
displayAttribute(index, state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditEntryWidget::revealCurrentAttribute()
|
||||||
|
{
|
||||||
|
if (! m_advancedUi->attributesEdit->isEnabled()) {
|
||||||
|
QModelIndex index = m_advancedUi->attributesView->currentIndex();
|
||||||
|
if (index.isValid()) {
|
||||||
|
QString key = m_attributesModel->keyByIndex(index);
|
||||||
|
m_advancedUi->attributesEdit->setPlainText(m_entryAttributes->value(key));
|
||||||
|
m_advancedUi->attributesEdit->setEnabled(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -730,8 +787,13 @@ void EditEntryWidget::removeCurrentAttachment()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString key = m_attachmentsModel->keyByIndex(index);
|
QMessageBox::StandardButton ans = MessageBox::question(this, tr("Confirm Remove"),
|
||||||
m_entryAttachments->remove(key);
|
tr("Are you sure you want to remove this attachment?"),
|
||||||
|
QMessageBox::Yes | QMessageBox::No);
|
||||||
|
if (ans == QMessageBox::Yes) {
|
||||||
|
QString key = m_attachmentsModel->keyByIndex(index);
|
||||||
|
m_entryAttachments->remove(key);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditEntryWidget::updateAutoTypeEnabled()
|
void EditEntryWidget::updateAutoTypeEnabled()
|
||||||
|
@ -76,6 +76,8 @@ private Q_SLOTS:
|
|||||||
void editCurrentAttribute();
|
void editCurrentAttribute();
|
||||||
void removeCurrentAttribute();
|
void removeCurrentAttribute();
|
||||||
void updateCurrentAttribute();
|
void updateCurrentAttribute();
|
||||||
|
void protectCurrentAttribute(bool state);
|
||||||
|
void revealCurrentAttribute();
|
||||||
void insertAttachment();
|
void insertAttachment();
|
||||||
void saveCurrentAttachment();
|
void saveCurrentAttachment();
|
||||||
void openAttachment(const QModelIndex& index);
|
void openAttachment(const QModelIndex& index);
|
||||||
@ -110,6 +112,8 @@ private:
|
|||||||
QMenu* createPresetsMenu();
|
QMenu* createPresetsMenu();
|
||||||
void updateEntryData(Entry* entry) const;
|
void updateEntryData(Entry* entry) const;
|
||||||
|
|
||||||
|
void displayAttribute(QModelIndex index, bool showProtected);
|
||||||
|
|
||||||
Entry* m_entry;
|
Entry* m_entry;
|
||||||
Database* m_database;
|
Database* m_database;
|
||||||
|
|
||||||
|
@ -28,19 +28,50 @@
|
|||||||
<property name="title">
|
<property name="title">
|
||||||
<string>Additional attributes</string>
|
<string>Additional attributes</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||||
<item>
|
<item>
|
||||||
<widget class="AttributesListView" name="attributesView"/>
|
<widget class="QSplitter" name="attributesSplitter">
|
||||||
</item>
|
<property name="orientation">
|
||||||
<item>
|
<enum>Qt::Horizontal</enum>
|
||||||
<widget class="QPlainTextEdit" name="attributesEdit">
|
</property>
|
||||||
<property name="enabled">
|
<property name="childrenCollapsible">
|
||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
|
<widget class="AttributesListView" name="attributesView">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="sizeAdjustPolicy">
|
||||||
|
<enum>QAbstractScrollArea::AdjustToContents</enum>
|
||||||
|
</property>
|
||||||
|
<property name="resizeMode">
|
||||||
|
<enum>QListView::Adjust</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QPlainTextEdit" name="attributesEdit">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Expanding">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>170</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
<layout class="QVBoxLayout" name="attributesButtonLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="addAttributeButton">
|
<widget class="QPushButton" name="addAttributeButton">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
@ -48,16 +79,6 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="editAttributeButton">
|
|
||||||
<property name="enabled">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Edit</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="removeAttributeButton">
|
<widget class="QPushButton" name="removeAttributeButton">
|
||||||
<property name="enabled">
|
<property name="enabled">
|
||||||
@ -68,6 +89,16 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="editAttributeButton">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Edit Name</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<spacer name="verticalSpacer">
|
<spacer name="verticalSpacer">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
@ -81,6 +112,35 @@
|
|||||||
</property>
|
</property>
|
||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="protectAttributeButton">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">margin-left:50%;margin-right:50%</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Protect</string>
|
||||||
|
</property>
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="revealAttributeButton">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Reveal</string>
|
||||||
|
</property>
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
@ -103,7 +163,7 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
<layout class="QVBoxLayout" name="attachmentsButtonLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="addAttachmentButton">
|
<widget class="QPushButton" name="addAttachmentButton">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
@ -172,11 +232,12 @@
|
|||||||
<tabstop>attributesView</tabstop>
|
<tabstop>attributesView</tabstop>
|
||||||
<tabstop>attributesEdit</tabstop>
|
<tabstop>attributesEdit</tabstop>
|
||||||
<tabstop>addAttributeButton</tabstop>
|
<tabstop>addAttributeButton</tabstop>
|
||||||
<tabstop>editAttributeButton</tabstop>
|
|
||||||
<tabstop>removeAttributeButton</tabstop>
|
<tabstop>removeAttributeButton</tabstop>
|
||||||
|
<tabstop>editAttributeButton</tabstop>
|
||||||
<tabstop>attachmentsView</tabstop>
|
<tabstop>attachmentsView</tabstop>
|
||||||
<tabstop>addAttachmentButton</tabstop>
|
<tabstop>addAttachmentButton</tabstop>
|
||||||
<tabstop>removeAttachmentButton</tabstop>
|
<tabstop>removeAttachmentButton</tabstop>
|
||||||
|
<tabstop>openAttachmentButton</tabstop>
|
||||||
<tabstop>saveAttachmentButton</tabstop>
|
<tabstop>saveAttachmentButton</tabstop>
|
||||||
</tabstops>
|
</tabstops>
|
||||||
<resources/>
|
<resources/>
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include <QFont>
|
#include <QFont>
|
||||||
#include <QMimeData>
|
#include <QMimeData>
|
||||||
|
#include <QPalette>
|
||||||
|
|
||||||
#include "core/DatabaseIcons.h"
|
#include "core/DatabaseIcons.h"
|
||||||
#include "core/Entry.h"
|
#include "core/Entry.h"
|
||||||
@ -127,8 +128,10 @@ QVariant EntryModel::data(const QModelIndex& index, int role) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
Entry* entry = entryFromIndex(index);
|
Entry* entry = entryFromIndex(index);
|
||||||
|
EntryAttributes* attr = entry->attributes();
|
||||||
|
|
||||||
if (role == Qt::DisplayRole) {
|
if (role == Qt::DisplayRole) {
|
||||||
|
QString result;
|
||||||
switch (index.column()) {
|
switch (index.column()) {
|
||||||
case ParentGroup:
|
case ParentGroup:
|
||||||
if (entry->group()) {
|
if (entry->group()) {
|
||||||
@ -136,11 +139,23 @@ QVariant EntryModel::data(const QModelIndex& index, int role) const
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Title:
|
case Title:
|
||||||
return entry->title();
|
result = entry->resolvePlaceholder(entry->title());
|
||||||
|
if (attr->isReference(EntryAttributes::TitleKey)) {
|
||||||
|
result.prepend(tr("Ref: ","Reference abbreviation"));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
case Username:
|
case Username:
|
||||||
return entry->username();
|
result = entry->resolvePlaceholder(entry->username());
|
||||||
|
if (attr->isReference(EntryAttributes::UserNameKey)) {
|
||||||
|
result.prepend(tr("Ref: ","Reference abbreviation"));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
case Url:
|
case Url:
|
||||||
return entry->url();
|
result = entry->resolvePlaceholder(entry->url());
|
||||||
|
if (attr->isReference(EntryAttributes::URLKey)) {
|
||||||
|
result.prepend(tr("Ref: ","Reference abbreviation"));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (role == Qt::DecorationRole) {
|
else if (role == Qt::DecorationRole) {
|
||||||
@ -166,6 +181,12 @@ QVariant EntryModel::data(const QModelIndex& index, int role) const
|
|||||||
}
|
}
|
||||||
return font;
|
return font;
|
||||||
}
|
}
|
||||||
|
else if (role == Qt::TextColorRole) {
|
||||||
|
if (entry->hasReferences()) {
|
||||||
|
QPalette p;
|
||||||
|
return QVariant(p.color(QPalette::Active, QPalette::Mid));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
@ -181,6 +181,12 @@ void TestEntryModel::testAttributesModel()
|
|||||||
QCOMPARE(spyAboutToRemove.count(), 1);
|
QCOMPARE(spyAboutToRemove.count(), 1);
|
||||||
QCOMPARE(spyRemoved.count(), 1);
|
QCOMPARE(spyRemoved.count(), 1);
|
||||||
|
|
||||||
|
// test attribute protection
|
||||||
|
QString value = entryAttributes->value("2nd");
|
||||||
|
entryAttributes->set("2nd", value, true);
|
||||||
|
QVERIFY(entryAttributes->isProtected("2nd"));
|
||||||
|
QCOMPARE(entryAttributes->value("2nd"), value);
|
||||||
|
|
||||||
QSignalSpy spyReset(model, SIGNAL(modelReset()));
|
QSignalSpy spyReset(model, SIGNAL(modelReset()));
|
||||||
entryAttributes->clear();
|
entryAttributes->clear();
|
||||||
model->setEntryAttributes(0);
|
model->setEntryAttributes(0);
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#include <QMimeData>
|
#include <QMimeData>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QSpinBox>
|
#include <QSpinBox>
|
||||||
|
#include <QPlainTextEdit>
|
||||||
#include <QTemporaryFile>
|
#include <QTemporaryFile>
|
||||||
#include <QTest>
|
#include <QTest>
|
||||||
#include <QToolBar>
|
#include <QToolBar>
|
||||||
@ -242,6 +243,19 @@ void TestGui::testEditEntry()
|
|||||||
QLineEdit* titleEdit = editEntryWidget->findChild<QLineEdit*>("titleEdit");
|
QLineEdit* titleEdit = editEntryWidget->findChild<QLineEdit*>("titleEdit");
|
||||||
QTest::keyClicks(titleEdit, "_test");
|
QTest::keyClicks(titleEdit, "_test");
|
||||||
|
|
||||||
|
// Test protected attributes
|
||||||
|
editEntryWidget->setCurrentPage(1);
|
||||||
|
QPlainTextEdit* attrTextEdit = editEntryWidget->findChild<QPlainTextEdit*>("attributesEdit");
|
||||||
|
QTest::mouseClick(editEntryWidget->findChild<QAbstractButton*>("addAttributeButton"), Qt::LeftButton);
|
||||||
|
QString attrText = "TEST TEXT";
|
||||||
|
QTest::keyClicks(attrTextEdit, attrText);
|
||||||
|
QCOMPARE(attrTextEdit->toPlainText(), attrText);
|
||||||
|
QTest::mouseClick(editEntryWidget->findChild<QAbstractButton*>("protectAttributeButton"), Qt::LeftButton);
|
||||||
|
QVERIFY(attrTextEdit->toPlainText().contains("PROTECTED"));
|
||||||
|
QTest::mouseClick(editEntryWidget->findChild<QAbstractButton*>("revealAttributeButton"), Qt::LeftButton);
|
||||||
|
QCOMPARE(attrTextEdit->toPlainText(), attrText);
|
||||||
|
editEntryWidget->setCurrentPage(0);
|
||||||
|
|
||||||
// Save the edit
|
// Save the edit
|
||||||
QDialogButtonBox* editEntryWidgetButtonBox = editEntryWidget->findChild<QDialogButtonBox*>("buttonBox");
|
QDialogButtonBox* editEntryWidgetButtonBox = editEntryWidget->findChild<QDialogButtonBox*>("buttonBox");
|
||||||
QTest::mouseClick(editEntryWidgetButtonBox->button(QDialogButtonBox::Ok), Qt::LeftButton);
|
QTest::mouseClick(editEntryWidgetButtonBox->button(QDialogButtonBox::Ok), Qt::LeftButton);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user