Merge branch 'develop' into meta/release-preparation

This commit is contained in:
Janek Bevendorff 2017-01-28 23:02:57 +01:00
commit 5652018cde
No known key found for this signature in database
GPG Key ID: CFEC2F6850BFFA53
15 changed files with 140 additions and 62 deletions

View File

@ -1,31 +1,32 @@
# Contributing to KeePassX Reboot
# Contributing to KeePassXC
:+1::tada: First off, thanks for taking the time to contribute! :tada::+1:
The following is a set of guidelines for contributing to KeePassX Reboot on GitHub.
The following is a set of guidelines for contributing to KeePassXC on GitHub.
These are just guidelines, not rules. Use your best judgment, and feel free to propose changes to this document in a pull request.
#### Table Of Contents
#### Table of contents
[What should I know before I get started?](#what-should-i-know-before-i-get-started)
* [Open Source Contribution Policy](#open-source-contribution-policy)
[How Can I Contribute?](#how-can-i-contribute)
* [Feature Requests](#feature-requests)
* [Bug Reports](#bug-reports)
* [Your First Code Contribution](#your-first-code-contribution)
* [Pull Requests](#pull-requests)
[How can I contribute?](#how-can-i-contribute)
* [Feature requests](#feature-requests)
* [Bug reports](#bug-reports)
* [Discuss with the team](#discuss-with-the-team)
* [Your first code contribution](#your-first-code-contribution)
* [Pull requests](#pull-requests)
* [Translations](#translations)
[Styleguides](#styleguides)
* [Git Branch Strategy](#git_branch_strategy)
* [Git Commit Messages](#git-commit-messages)
* [Coding Styleguide](#coding-styleguide)
* [Git branch strategy](#git-branch-strategy)
* [Git commit messages](#git-commit-messages)
* [Coding styleguide](#coding-styleguide)
## What should I know before I get started?
### Open Source Contribution Policy
[Version 0.3, 20151118](https://medium.com/@jmaynard/a-contribution-policy-for-open-source-that-works-bfc4600c9d83#.i9ntbhmad)
**Source**: [Version 0.3, 20151118](https://medium.com/@jmaynard/a-contribution-policy-for-open-source-that-works-bfc4600c9d83#.i9ntbhmad)
#### Policy
@ -49,35 +50,35 @@ If we reject your contribution, it means only that we do not consider it suitabl
* 0.3, 20111119: Added “irrevocably” to “we can use” and changed “it” to “your contribution” in the “if rejected” section. Thanks to Patrick Maupin.
## How Can I Contribute?
### Feature Requests
## How can I contribute?
### Feature requests
We're always looking for suggestions to improve our application. If you have a suggestion for improving an existing feature, or would like to suggest a completely new feature for KeePassX Reboot, please use the Issues section or our [Google Groups](https://groups.google.com/forum/#!forum/keepassx-reboot) forum.
We're always looking for suggestions to improve our application. If you have a suggestion to improve an existing feature, or would like to suggest a completely new feature for KeePassXC, please use the [issue tracker on GitHub][issues-section]. For more general discussion, try using our [Google Groups][google-groups] forum.
### Bug Reports
### Bug reports
Our software isn't always perfect, but we strive to always improve our work. You may file bug reports in the Issues section.
Our software isn't always perfect, but we strive to always improve our work. You may file bug reports in the issue tracker.
Before submitting a Bug Report, check if the problem has already been reported. Please refrain from opening a duplicate issue. If you want to highlight a deficiency on an existing issue, simply add a comment.
Before submitting a bug report, check if the problem has already been reported. Please refrain from opening a duplicate issue. If you want to add further information to an existing issue, simply add a comment on that issue.
### Discuss with the Team
### Discuss with the team
You can talk to the KeePassX Reboot Team about Bugs, new feature, Issue and PullRequests at our [Google Groups](https://groups.google.com/forum/#!forum/keepassx-reboot) forum
As with feature requests, you can talk to the KeePassXC team about bugs, new features, other issues and pull requests on the dedicated issue tracker, using the [Google Groups][google-groups] forum, or in the IRC channel on Freenode (`#keepassxc-dev` on `irc.freenode.net`, or use a [webchat link](https://webchat.freenode.net/?channels=%23keepassxc-dev)).
### Your First Code Contribution
### Your first code contribution
Unsure where to begin contributing to KeePassX Reboot? You can start by looking through these `beginner` and `help-wanted` issues:
Unsure where to begin contributing to KeePassXC? You can start by looking through these `beginner` and `help-wanted` issues:
* [Beginner issues][beginner] - issues which should only require a few lines of code, and a test or two.
* [Help wanted issues][help-wanted] - issues which should be a bit more involved than `beginner` issues.
* [Beginner issues][beginner] issues which should only require a few lines of code, and a test or two.
* ['Help wanted' issues][help-wanted] issues which should be a bit more involved than `beginner` issues.
Both issue lists are sorted by total number of comments. While not perfect, number of comments is a reasonable proxy for impact a given change will have.
Both issue lists are sorted by total number of comments. While not perfect, looking at the number of comments on an issue can give a general idea of how much an impact a given change will have.
### Pull Requests
### Pull requests
Along with our desire to hear your feedback and suggestions, we're also interested in accepting direct assistance in the form of code.
All pull requests must comply with the above requirements and with the [Styleguides](#styleguides).
All pull requests must comply with the above requirements and with the [styleguides](#styleguides).
### Translations
@ -86,19 +87,20 @@ Please join an existing language team or request a new one if there is none.
## Styleguides
### Git Branch Strategy
### Git branch strategy
The Branch Strategy is based on [git-flow-lite](http://nvie.com/posts/a-successful-git-branching-model/).
* **master** -> always points to the last release published
* **develop** -> points to the next planned release, tested and reviewed code
* **feature/**[name] -> points to brand new feature in codebase, candidate for merge into develop (subject to rebase)
* **master** points to the latest public release
* **develop** points to the development of the next release, contains tested and reviewed code
* **feature/**[name] points to a branch with a new feature, one which is candidate for merge into develop (subject to rebase)
* **hotfix/**[id]-[description] points to a branch with a fix for a particular issue ID
### Git Commit Messages
### Git commit messages
* Use the present tense ("Add feature" not "Added feature")
* Use the imperative mood ("Move cursor to..." not "Moves cursor to...")
* Use the imperative mood ("Move cursor to…" not "Moves cursor to…")
* Limit the first line to 72 characters or less
* Reference issues and pull requests liberally
* When only changing documentation, include `[ci skip]` in the commit description
@ -114,21 +116,21 @@ The Branch Strategy is based on [git-flow-lite](http://nvie.com/posts/a-successf
* :lock: `:lock:` when dealing with security
### Coding Styleguide
### Coding styleguide
This project follows the [Qt Coding Style](https://wiki.qt.io/Qt_Coding_Style). All submissions are expected to follow this style.
In particular Code must follow the following specific rules:
In particular, code must stick to the following rules:
#### Naming Convention
#### Naming convention
`lowerCamelCase`
For names made of only one word, the fist letter is lowercase.
For names made of multiple concatenated words, the first letter is lowercase and each subsequent concatenated word is capitalized.
For names made of only one word, the first letter should be lowercase.
For names made of multiple concatenated words, the first letter of the whole is lowercase, and the first letter of each subsequent word is capitalized.
#### Indention
For C++ files (.cpp .h): 4 spaces
For Qt-UI files (.ui): 2 spaces
For **C++ files** (*.cpp .h*): 4 spaces
For **Qt-UI files** (*.ui*): 2 spaces
#### Pointers
```c
@ -165,9 +167,8 @@ Use prefix: `m_*`
Example: `m_variable`
#### GUI Widget names
Widget names must be related to the desired program behaviour.
Preferably end the name with the Widget Classname
#### GUI widget names
Widget names must be related to the desired program behavior, and preferably end with the widget's classname.
Example: `<widget class="QCheckBox" name="rememberCheckBox">`
@ -175,3 +176,5 @@ Example: `<widget class="QCheckBox" name="rememberCheckBox">`
[beginner]:https://github.com/keepassxreboot/keepassx/issues?q=is%3Aopen+is%3Aissue+label%3Abeginner+label%3A%22help+wanted%22+sort%3Acomments-desc
[help-wanted]:https://github.com/keepassxreboot/keepassx/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22+sort%3Acomments-desc
[issues-section]:https://github.com/keepassxreboot/keepassxc/issues
[google-groups]:https://groups.google.com/forum/#!forum/keepassx-reboot

View File

@ -98,7 +98,9 @@ QString AutoTypePlatformMac::activeWindowTitle()
if (windowLayer(window) == 0) {
// First toplevel window in list (front to back order)
title = windowTitle(window);
break;
if (!title.isEmpty()) {
break;
}
}
}

View File

@ -353,6 +353,12 @@ void Entry::setTitle(const QString& title)
void Entry::setUrl(const QString& url)
{
bool remove = url != m_attributes->value(EntryAttributes::URLKey) &&
(m_attributes->value(EntryAttributes::RememberCmdExecAttr) == "1" ||
m_attributes->value(EntryAttributes::RememberCmdExecAttr) == "0");
if (remove) {
m_attributes->remove(EntryAttributes::RememberCmdExecAttr);
}
m_attributes->set(EntryAttributes::URLKey, url, m_attributes->isProtected(EntryAttributes::URLKey));
}
@ -508,7 +514,8 @@ Entry* Entry::clone(CloneFlags flags) const
entry->m_data.timeInfo.setLocationChanged(now);
}
if (flags & CloneRenameTitle)
entry->setTitle(entry->title() + tr(" - Clone"));
return entry;
}

View File

@ -115,7 +115,8 @@ public:
CloneNoFlags = 0,
CloneNewUuid = 1, // generate a random uuid for the clone
CloneResetTimeInfo = 2, // set all TimeInfo attributes to the current time
CloneIncludeHistory = 4 // clone the history items
CloneIncludeHistory = 4, // clone the history items
CloneRenameTitle = 8 // add "-Clone" after the original title
};
Q_DECLARE_FLAGS(CloneFlags, CloneFlag)

View File

@ -24,6 +24,7 @@ const QString EntryAttributes::URLKey = "URL";
const QString EntryAttributes::NotesKey = "Notes";
const QStringList EntryAttributes::DefaultAttributes(QStringList() << TitleKey << UserNameKey
<< PasswordKey << URLKey << NotesKey);
const QString EntryAttributes::RememberCmdExecAttr = "_EXEC_CMD";
EntryAttributes::EntryAttributes(QObject* parent)
: QObject(parent)

View File

@ -52,6 +52,7 @@ public:
static const QString URLKey;
static const QString NotesKey;
static const QStringList DefaultAttributes;
static const QString RememberCmdExecAttr;
static bool isDefaultAttribute(const QString& key);
Q_SIGNALS:

View File

@ -42,7 +42,11 @@ QList<Entry*> EntrySearcher::searchEntries(const QString& searchTerm, const Grou
const QList<Group*> children = group->children();
for (Group* childGroup : children) {
if (childGroup->searchingEnabled() != Group::Disable) {
searchResult.append(searchEntries(searchTerm, childGroup, caseSensitivity));
if (matchGroup(searchTerm, childGroup, caseSensitivity)) {
searchResult.append(childGroup->entriesRecursive());
} else {
searchResult.append(searchEntries(searchTerm, childGroup, caseSensitivity));
}
}
}
@ -69,3 +73,21 @@ bool EntrySearcher::wordMatch(const QString& word, Entry* entry, Qt::CaseSensiti
entry->url().contains(word, caseSensitivity) ||
entry->notes().contains(word, caseSensitivity);
}
bool EntrySearcher::matchGroup(const QString& searchTerm, const Group* group, Qt::CaseSensitivity caseSensitivity)
{
const QStringList wordList = searchTerm.split(QRegExp("\\s"), QString::SkipEmptyParts);
for (const QString& word : wordList) {
if (!wordMatch(word, group, caseSensitivity)) {
return false;
}
}
return true;
}
bool EntrySearcher::wordMatch(const QString& word, const Group* group, Qt::CaseSensitivity caseSensitivity)
{
return group->name().contains(word, caseSensitivity) ||
group->notes().contains(word, caseSensitivity);
}

View File

@ -33,6 +33,8 @@ private:
QList<Entry*> searchEntries(const QString& searchTerm, const Group* group, Qt::CaseSensitivity caseSensitivity);
QList<Entry*> matchEntry(const QString& searchTerm, Entry* entry, Qt::CaseSensitivity caseSensitivity);
bool wordMatch(const QString& word, Entry* entry, Qt::CaseSensitivity caseSensitivity);
bool matchGroup(const QString& searchTerm, const Group* group, Qt::CaseSensitivity caseSensitivity);
bool wordMatch(const QString& word, const Group* group, Qt::CaseSensitivity caseSensitivity);
};
#endif // KEEPASSX_ENTRYSEARCHER_H

View File

@ -388,7 +388,7 @@ void KeePass2XmlReader::parseBinaries()
QString id = attr.value("ID").toString();
QByteArray data;
if (attr.value("Compressed").compare("True", Qt::CaseInsensitive) == 0) {
if (attr.value("Compressed").compare(QLatin1String("True"), Qt::CaseInsensitive) == 0) {
data = readCompressedBinary();
}
else {

View File

@ -19,6 +19,7 @@
#include <QAction>
#include <QDesktopServices>
#include <QCheckBox>
#include <QHBoxLayout>
#include <QLabel>
#include <QFile>
@ -312,8 +313,10 @@ void DatabaseWidget::cloneEntry()
return;
}
Entry* entry = currentEntry->clone(Entry::CloneNewUuid | Entry::CloneResetTimeInfo);
Entry* entry = currentEntry->clone(Entry::CloneNewUuid | Entry::CloneResetTimeInfo | Entry::CloneRenameTitle);
entry->setGroup(currentEntry->group());
if (isInSearchMode())
search(m_lastSearchText);
m_entryView->setFocus();
m_entryView->setCurrentEntry(entry);
}
@ -494,8 +497,46 @@ void DatabaseWidget::openUrlForEntry(Entry* entry)
}
if (urlString.startsWith("cmd://")) {
// check if decision to execute command was stored
if (entry->attributes()->hasKey(EntryAttributes::RememberCmdExecAttr)) {
if (entry->attributes()->value(EntryAttributes::RememberCmdExecAttr) == "1") {
QProcess::startDetached(urlString.mid(6));
}
return;
}
// otherwise ask user
if (urlString.length() > 6) {
QProcess::startDetached(urlString.mid(6));
QString cmdTruncated = urlString.mid(6);
if (cmdTruncated.length() > 400)
cmdTruncated = cmdTruncated.left(400) + " […]";
QMessageBox msgbox(QMessageBox::Icon::Question,
tr("Execute command?"),
tr("Do you really want to execute the following command?<br><br>%1<br>")
.arg(cmdTruncated.toHtmlEscaped()),
QMessageBox::Yes | QMessageBox::No,
this
);
msgbox.setDefaultButton(QMessageBox::No);
QCheckBox* checkbox = new QCheckBox(tr("Remember my choice"), &msgbox);
msgbox.setCheckBox(checkbox);
bool remember = false;
QObject::connect(checkbox, &QCheckBox::stateChanged, [&](int state) {
if (static_cast<Qt::CheckState>(state) == Qt::CheckState::Checked) {
remember = true;
}
});
int result = msgbox.exec();
if (result == QMessageBox::Yes) {
QProcess::startDetached(urlString.mid(6));
}
if (remember) {
entry->attributes()->set(EntryAttributes::RememberCmdExecAttr,
result == QMessageBox::Yes ? "1" : "0");
}
}
}
else {
@ -750,7 +791,7 @@ void DatabaseWidget::entryActivationSignalReceived(Entry* entry, EntryModel::Mod
void DatabaseWidget::switchToEntryEdit()
{
Entry* entry = m_entryView->currentEntry();
Q_ASSERT(entry);
if (!entry) {
return;
}
@ -761,7 +802,7 @@ void DatabaseWidget::switchToEntryEdit()
void DatabaseWidget::switchToGroupEdit()
{
Group* group = m_groupView->currentGroup();
Q_ASSERT(group);
if (!group) {
return;
}

View File

@ -364,7 +364,7 @@ void MainWindow::setMenuActionState(DatabaseWidget::Mode mode)
bool groupSelected = dbWidget->isGroupSelected();
m_ui->actionEntryNew->setEnabled(!inSearch);
m_ui->actionEntryClone->setEnabled(singleEntrySelected && !inSearch);
m_ui->actionEntryClone->setEnabled(singleEntrySelected);
m_ui->actionEntryEdit->setEnabled(singleEntrySelected);
m_ui->actionEntryDelete->setEnabled(entriesSelected);
m_ui->actionEntryCopyTitle->setEnabled(singleEntrySelected && dbWidget->currentEntryHasTitle());

View File

@ -41,6 +41,7 @@ SearchWidget::SearchWidget(QWidget *parent)
connect(this, SIGNAL(escapePressed()), m_ui->searchEdit, SLOT(clear()));
new QShortcut(Qt::CTRL + Qt::Key_F, this, SLOT(searchFocus()), nullptr, Qt::ApplicationShortcut);
new QShortcut(Qt::Key_Escape, m_ui->searchEdit, SLOT(clear()), nullptr, Qt::ApplicationShortcut);
m_ui->searchEdit->installEventFilter(this);

View File

@ -89,6 +89,7 @@ void EditEntryWidget::setupMain()
add(tr("Entry"), m_mainWidget);
m_mainUi->togglePasswordButton->setIcon(filePath()->onOffIcon("actions", "password-show"));
m_mainUi->togglePasswordGeneratorButton->setIcon(filePath()->icon("actions", "password-generator", false));
connect(m_mainUi->togglePasswordButton, SIGNAL(toggled(bool)), m_mainUi->passwordEdit, SLOT(setShowPassword(bool)));
connect(m_mainUi->togglePasswordGeneratorButton, SIGNAL(toggled(bool)), SLOT(togglePasswordGeneratorButton(bool)));
connect(m_mainUi->expireCheck, SIGNAL(toggled(bool)), m_mainUi->expireDatePicker, SLOT(setEnabled(bool)));
@ -433,6 +434,9 @@ void EditEntryWidget::saveEntry()
void EditEntryWidget::updateEntryData(Entry* entry) const
{
entry->attributes()->copyCustomKeysFrom(m_entryAttributes);
entry->attachments()->copyDataFrom(m_entryAttachments);
entry->setTitle(m_mainUi->titleEdit->text());
entry->setUsername(m_mainUi->usernameEdit->text());
entry->setUrl(m_mainUi->urlEdit->text());
@ -442,9 +446,6 @@ void EditEntryWidget::updateEntryData(Entry* entry) const
entry->setNotes(m_mainUi->notesEdit->toPlainText());
entry->attributes()->copyCustomKeysFrom(m_entryAttributes);
entry->attachments()->copyDataFrom(m_entryAttachments);
IconStruct iconStruct = m_iconsWidget->state();
if (iconStruct.number < 0) {

View File

@ -77,9 +77,6 @@
</item>
<item>
<widget class="QToolButton" name="togglePasswordGeneratorButton">
<property name="text">
<string>Generate</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>

View File

@ -481,8 +481,7 @@ void TestGui::testSearch()
QCOMPARE(entry->title(), origTitle.append("_edited"));
// Cancel search, should return to normal view
QTest::mouseClick(searchTextEdit, Qt::LeftButton);
QTest::keyClick(searchTextEdit, Qt::Key_Escape);
QTest::keyClick(m_mainWindow, Qt::Key_Escape);
QTRY_COMPARE(m_dbWidget->currentMode(), DatabaseWidget::ViewMode);
}
@ -567,7 +566,7 @@ void TestGui::testCloneEntry()
QCOMPARE(entryView->model()->rowCount(), 2);
Entry* entryClone = entryView->entryFromIndex(entryView->model()->index(1, 1));
QVERIFY(entryOrg->uuid() != entryClone->uuid());
QCOMPARE(entryClone->title(), entryOrg->title());
QCOMPARE(entryClone->title(), entryOrg->title() + QString(" - Clone"));
}
void TestGui::testDragAndDropEntry()