Merge github.com:keepassx/keepassx

Conflicts:
	src/gui/DatabaseWidget.cpp
This commit is contained in:
Sebastien Fricker 2014-06-09 09:54:29 +02:00
commit 95fdefdcc7
72 changed files with 3740 additions and 399 deletions

View file

@ -36,6 +36,7 @@ set(keepassx_SOURCES
core/Entry.cpp
core/EntryAttachments.cpp
core/EntryAttributes.cpp
core/EntrySearcher.cpp
core/FilePath.cpp
core/Global.h
core/Group.cpp
@ -48,7 +49,9 @@ set(keepassx_SOURCES
core/SignalMultiplexer.cpp
core/TimeDelta.cpp
core/TimeInfo.cpp
core/ToDbExporter.cpp
core/Tools.cpp
core/Translator.cpp
core/Uuid.cpp
core/qcommandlineoption.cpp
core/qcommandlineparser.cpp
@ -74,6 +77,7 @@ set(keepassx_SOURCES
gui/DatabaseSettingsWidget.cpp
gui/DatabaseTabWidget.cpp
gui/DatabaseWidget.cpp
gui/DatabaseWidgetStateSync.cpp
gui/DialogyWidget.cpp
gui/DragTabBar.cpp
gui/EditWidget.cpp
@ -156,6 +160,7 @@ set(keepassx_MOC
gui/DatabaseSettingsWidget.h
gui/DatabaseTabWidget.h
gui/DatabaseWidget.h
gui/DatabaseWidgetStateSync.h
gui/DialogyWidget.h
gui/DragTabBar.h
gui/EditWidget.h

View file

@ -190,8 +190,10 @@ void AutoType::performGlobalAutoType(const QList<Database*>& dbList)
if (entryList.isEmpty()) {
m_inAutoType = false;
MessageBox::information(Q_NULLPTR, tr("Auto-Type - KeePassX"),
tr("Couldn't find an entry that matches the window title."));
QString message = tr("Couldn't find an entry that matches the window title:");
message.append("\n\n");
message.append(windowTitle);
MessageBox::information(Q_NULLPTR, tr("Auto-Type - KeePassX"), message);
}
else if ((entryList.size() == 1) && !config()->get("security/autotypeask").toBool()) {
m_inAutoType = false;
@ -503,6 +505,12 @@ QString AutoType::autoTypeSequence(const Entry* entry, const QString& windowTitl
}
}
if (!match && config()->get("AutoTypeEntryTitleMatch").toBool() && !entry->title().isEmpty()
&& windowTitle.contains(entry->title(), Qt::CaseInsensitive)) {
sequence = entry->defaultAutoTypeSequence();
match = true;
}
if (!match) {
return QString();
}

View file

@ -6,6 +6,7 @@
#define KEEPASSX_VERSION "${KEEPASSX_VERSION}"
#define KEEPASSX_SOURCE_DIR "${CMAKE_SOURCE_DIR}"
#define KEEPASSX_BINARY_DIR "${CMAKE_BINARY_DIR}"
#define KEEPASSX_PLUGIN_DIR "${PLUGIN_INSTALL_DIR}"

View file

@ -95,12 +95,14 @@ void Config::init(const QString& fileName)
m_defaults.insert("ShowToolbar", true);
m_defaults.insert("MinimizeOnCopy", false);
m_defaults.insert("UseGroupIconOnEntryCreation", false);
m_defaults.insert("AutoTypeEntryTitleMatch", true);
m_defaults.insert("security/clearclipboard", true);
m_defaults.insert("security/clearclipboardtimeout", 10);
m_defaults.insert("security/lockdatabaseidle", false);
m_defaults.insert("security/lockdatabaseidlesec", 10);
m_defaults.insert("security/passwordscleartext", false);
m_defaults.insert("security/autotypeask", false);
m_defaults.insert("security/autotypeask", true);
m_defaults.insert("GUI/Language", "system");
}
Config* Config::instance()
@ -112,7 +114,7 @@ Config* Config::instance()
return m_instance;
}
void Config::createConfigFromFile(QString file)
void Config::createConfigFromFile(const QString& file)
{
Q_ASSERT(!m_instance);
m_instance = new Config(file, qApp);

View file

@ -36,7 +36,7 @@ public:
void set(const QString& key, const QVariant& value);
static Config* instance();
static void createConfigFromFile(QString file);
static void createConfigFromFile(const QString& file);
static void createTempFileInstance();
private:

View file

@ -579,25 +579,6 @@ const Database* Entry::database() const
}
}
bool Entry::match(const QString& searchTerm, Qt::CaseSensitivity caseSensitivity)
{
QStringList wordList = searchTerm.split(QRegExp("\\s"), QString::SkipEmptyParts);
Q_FOREACH (const QString& word, wordList) {
if (!wordMatch(word, caseSensitivity)) {
return false;
}
}
return true;
}
bool Entry::wordMatch(const QString& word, Qt::CaseSensitivity caseSensitivity)
{
return title().contains(word, caseSensitivity) ||
username().contains(word, caseSensitivity) ||
url().contains(word, caseSensitivity) ||
notes().contains(word, caseSensitivity);
}
QString Entry::resolvePlaceholders(const QString& str) const
{
QString result = str;

View file

@ -141,7 +141,6 @@ public:
void setGroup(Group* group);
void setUpdateTimeinfo(bool value);
bool match(const QString& searchTerm, Qt::CaseSensitivity caseSensitivity);
Q_SIGNALS:
/**
@ -157,7 +156,6 @@ private Q_SLOTS:
void updateModifiedSinceBegin();
private:
bool wordMatch(const QString& word, Qt::CaseSensitivity caseSensitivity);
const Database* database() const;
template <class T> bool set(T& property, const T& value);

View file

@ -0,0 +1,65 @@
/*
* Copyright (C) 2014 Florian Geyer <blueice@fobos.de>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "EntrySearcher.h"
#include "core/Group.h"
QList<Entry*> EntrySearcher::search(const QString &searchTerm, const Group* group, Qt::CaseSensitivity caseSensitivity)
{
if (!group->resolveSearchingEnabled()) {
return QList<Entry*>();
}
return searchEntries(searchTerm, group, caseSensitivity);
}
QList<Entry*> EntrySearcher::searchEntries(const QString& searchTerm, const Group* group, Qt::CaseSensitivity caseSensitivity)
{
QList<Entry*> searchResult;
Q_FOREACH (Entry* entry, group->entries()) {
searchResult.append(matchEntry(searchTerm, entry, caseSensitivity));
}
Q_FOREACH (Group* childGroup, group->children()) {
if (childGroup->searchingEnabled() != Group::Disable) {
searchResult.append(searchEntries(searchTerm, childGroup, caseSensitivity));
}
}
return searchResult;
}
QList<Entry*> EntrySearcher::matchEntry(const QString& searchTerm, Entry* entry, Qt::CaseSensitivity caseSensitivity)
{
QStringList wordList = searchTerm.split(QRegExp("\\s"), QString::SkipEmptyParts);
Q_FOREACH (const QString& word, wordList) {
if (!wordMatch(word, entry, caseSensitivity)) {
return QList<Entry*>();
}
}
return QList<Entry*>() << entry;
}
bool EntrySearcher::wordMatch(const QString& word, Entry* entry, Qt::CaseSensitivity caseSensitivity)
{
return entry->title().contains(word, caseSensitivity) ||
entry->username().contains(word, caseSensitivity) ||
entry->url().contains(word, caseSensitivity) ||
entry->notes().contains(word, caseSensitivity);
}

37
src/core/EntrySearcher.h Normal file
View file

@ -0,0 +1,37 @@
/*
* Copyright (C) 2014 Florian Geyer <debfx@fobos.de>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef KEEPASSX_ENTRYSEARCHER_H
#define KEEPASSX_ENTRYSEARCHER_H
#include <QString>
class Group;
class Entry;
class EntrySearcher
{
public:
QList<Entry*> search(const QString& searchTerm, const Group* group, Qt::CaseSensitivity caseSensitivity);
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);
};
#endif // KEEPASSX_ENTRYSEARCHER_H

14
src/core/Exporter.h Normal file
View file

@ -0,0 +1,14 @@
#ifndef KEEPASSX_EXPORTER_H
#define KEEPASSX_EXPORTER_H
class Database;
class Group;
class Exporter
{
public:
virtual Database* exportGroup(Group* group) = 0;
virtual ~Exporter() {}
};
#endif // KEEPASSX_EXPORTER_H

View file

@ -500,22 +500,6 @@ void Group::copyDataFrom(const Group* other)
m_lastTopVisibleEntry = other->m_lastTopVisibleEntry;
}
Database* Group::exportToDb()
{
Q_ASSERT(database());
Database* db = new Database();
Group* clonedGroup = clone(Entry::CloneNewUuid | Entry::CloneIncludeHistory);
clonedGroup->setParent(db->rootGroup());
QSet<Uuid> customIcons = customIconsRecursive();
db->metadata()->copyCustomIcons(customIcons, database()->metadata());
db->copyAttributesFrom(database());
return db;
}
void Group::addEntry(Entry* entry)
{
Q_ASSERT(entry);
@ -612,33 +596,6 @@ void Group::recCreateDelObjects()
}
}
QList<Entry*> Group::search(const QString& searchTerm, Qt::CaseSensitivity caseSensitivity,
bool resolveInherit)
{
QList<Entry*> searchResult;
bool search;
if (resolveInherit) {
search = resolveSearchingEnabled();
}
else if (searchingEnabled() == Disable) {
search = false;
}
else {
search = true;
}
if (search) {
Q_FOREACH (Entry* entry, m_entries) {
if (entry->match(searchTerm, caseSensitivity)) {
searchResult.append(entry);
}
}
Q_FOREACH (Group* group, m_children) {
searchResult.append(group->search(searchTerm, caseSensitivity, false));
}
}
return searchResult;
}
bool Group::resolveSearchingEnabled() const
{
switch (m_data.searchingEnabled) {

View file

@ -111,10 +111,6 @@ public:
*/
Group* clone(Entry::CloneFlags entryFlags = Entry::CloneNewUuid | Entry::CloneResetTimeInfo) const;
void copyDataFrom(const Group* other);
Database* exportToDb();
QList<Entry*> search(const QString& searchTerm, Qt::CaseSensitivity caseSensitivity,
bool resolveInherit = true);
Q_SIGNALS:
void dataChanged(Group* group);

39
src/core/ToDbExporter.cpp Normal file
View file

@ -0,0 +1,39 @@
/*
* Copyright (C) 2014 Felix Geyer <debfx@fobos.de>
* Copyright (C) 2014 Florian Geyer <blueice@fobos.de>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "ToDbExporter.h"
#include "core/Database.h"
#include "core/Group.h"
#include "core/Metadata.h"
Database* ToDbExporter::exportGroup(Group* group)
{
Database* oldDb = group->database();
Q_ASSERT(oldDb);
Database* db = new Database();
Group* clonedGroup = group->clone(Entry::CloneNewUuid | Entry::CloneIncludeHistory);
clonedGroup->setParent(db->rootGroup());
QSet<Uuid> customIcons = group->customIconsRecursive();
db->metadata()->copyCustomIcons(customIcons, oldDb->metadata());
db->copyAttributesFrom(oldDb);
return db;
}

33
src/core/ToDbExporter.h Normal file
View file

@ -0,0 +1,33 @@
/*
* Copyright (C) 2014 Felix Geyer <debfx@fobos.de>
* Copyright (C) 2014 Florian Geyer <blueice@fobos.de>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef KEEPASSX_TODBEXPORTER_H
#define KEEPASSX_TODBEXPORTER_H
#include "core/Exporter.h"
class Database;
class Group;
class ToDbExporter : Exporter
{
public:
Database* exportGroup(Group* group);
};
#endif // KEEPASSX_TODBEXPORTER_H

120
src/core/Translator.cpp Normal file
View file

@ -0,0 +1,120 @@
/*
* Copyright (C) 2014 Felix Geyer <debfx@fobos.de>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "Translator.h"
#include <QCoreApplication>
#include <QDir>
#include <QLibraryInfo>
#include <QLocale>
#include <QRegExp>
#include <QTranslator>
#include "config-keepassx.h"
#include "core/Config.h"
#include "core/FilePath.h"
void Translator::installTranslator()
{
QString language = config()->get("GUI/Language").toString();
if (language == "system" || language.isEmpty()) {
language = QLocale::system().name();
}
if (!installTranslator(language)) {
// English fallback still needs translations for plurals
if (!installTranslator("en_plurals")) {
qWarning("Couldn't load translations.");
}
}
installQtTranslator(language);
availableLanguages();
}
QList<QPair<QString, QString> > Translator::availableLanguages()
{
QStringList paths;
#ifdef QT_DEBUG
paths.append(QString("%1/share/translations").arg(KEEPASSX_BINARY_DIR));
#endif
paths.append(filePath()->dataPath("translations"));
QList<QPair<QString, QString> > languages;
languages.append(QPair<QString, QString>("system", "System default"));
QRegExp regExp("keepassx_([a-zA-Z_]+)\\.qm", Qt::CaseInsensitive, QRegExp::RegExp2);
Q_FOREACH (const QString& path, paths) {
Q_FOREACH (const QString& filename, QDir(path).entryList()) {
if (regExp.exactMatch(filename)) {
QString langcode = regExp.cap(1);
if (langcode == "en_plurals") {
langcode = "en";
}
languages.append(QPair<QString, QString>(langcode,
QLocale::languageToString(QLocale(langcode).language())));
}
}
}
return languages;
}
bool Translator::installTranslator(const QString& language)
{
QStringList paths;
#ifdef QT_DEBUG
paths.append(QString("%1/share/translations").arg(KEEPASSX_BINARY_DIR));
#endif
paths.append(filePath()->dataPath("translations"));
Q_FOREACH (const QString& path, paths) {
if (installTranslator(language, path)) {
return true;
}
}
return false;
}
bool Translator::installTranslator(const QString& language, const QString& path)
{
QTranslator* translator = new QTranslator(qApp);
if (translator->load(QString("keepassx_").append(language), path)) {
QCoreApplication::installTranslator(translator);
return true;
}
else {
delete translator;
return false;
}
}
bool Translator::installQtTranslator(const QString& language)
{
QTranslator* qtTranslator = new QTranslator(qApp);
if (qtTranslator->load(QString("%1/qt_%2").arg(QLibraryInfo::location(QLibraryInfo::TranslationsPath), language))) {
QCoreApplication::installTranslator(qtTranslator);
return true;
}
else {
delete qtTranslator;
return false;
}
}

36
src/core/Translator.h Normal file
View file

@ -0,0 +1,36 @@
/*
* Copyright (C) 2014 Felix Geyer <debfx@fobos.de>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef KEEPASSX_TRANSLATOR_H
#define KEEPASSX_TRANSLATOR_H
#include <QPair>
#include <QString>
class Translator
{
public:
static void installTranslator();
static QList<QPair<QString, QString> > availableLanguages();
private:
static bool installTranslator(const QString& language);
static bool installTranslator(const QString& language, const QString& path);
static bool installQtTranslator(const QString& language);
};
#endif // KEEPASSX_TRANSLATOR_H

View file

@ -51,6 +51,7 @@ void Clipboard::setText(const QString& text)
if (config()->get("security/clearclipboard").toBool()) {
int timeout = config()->get("security/clearclipboardtimeout").toInt();
if (timeout > 0) {
m_lastCopied = text;
m_timer->start(timeout * 1000);
}
}
@ -65,8 +66,12 @@ void Clipboard::clearClipboard()
return;
}
clipboard->clear(QClipboard::Clipboard);
if (clipboard->supportsSelection()) {
if (clipboard->text(QClipboard::Clipboard) == m_lastCopied) {
clipboard->clear(QClipboard::Clipboard);
}
if (clipboard->supportsSelection()
&& (clipboard->text(QClipboard::Selection) == m_lastCopied)) {
clipboard->clear(QClipboard::Selection);
}
@ -74,6 +79,8 @@ void Clipboard::clearClipboard()
QDBusMessage message = QDBusMessage::createMethodCall("org.kde.klipper", "/klipper", "", "clearClipboardHistory");
QDBusConnection::sessionBus().send(message);
#endif
m_lastCopied.clear();
}
void Clipboard::cleanup()

View file

@ -43,6 +43,7 @@ private:
static Clipboard* m_instance;
QTimer* m_timer;
QString m_lastCopied;
};
inline Clipboard* clipboard() {

View file

@ -117,8 +117,8 @@ void DatabaseOpenWidget::openDatabase()
Q_EMIT editFinished(true);
}
else {
MessageBox::warning(this, tr("Error"), tr("Unable to open the database.\n%1")
.arg(reader.errorString()));
MessageBox::warning(this, tr("Error"), tr("Unable to open the database.").append("\n")
.append(reader.errorString()));
m_ui->editPassword->clear();
}
}
@ -138,7 +138,7 @@ CompositeKey DatabaseOpenWidget::databaseKey()
QString keyFilename = m_ui->comboKeyFile->currentText();
QString errorMsg;
if (!key.load(keyFilename, &errorMsg)) {
MessageBox::warning(this, tr("Error"), tr("Can't open key file:\n%1").arg(errorMsg));
MessageBox::warning(this, tr("Error"), tr("Can't open key file").append(":\n").append(errorMsg));
return CompositeKey();
}
masterKey.addKey(key);

View file

@ -27,6 +27,7 @@
#include "core/Metadata.h"
#include "core/qsavefile.h"
#include "gui/DatabaseWidget.h"
#include "gui/DatabaseWidgetStateSync.h"
#include "gui/DragTabBar.h"
#include "gui/FileDialog.h"
#include "gui/MessageBox.h"
@ -46,12 +47,15 @@ const int DatabaseTabWidget::LastDatabasesCount = 5;
DatabaseTabWidget::DatabaseTabWidget(QWidget* parent)
: QTabWidget(parent)
, m_dbWidgetSateSync(new DatabaseWidgetStateSync(this))
{
DragTabBar* tabBar = new DragTabBar(this);
tabBar->setDrawBase(false);
setTabBar(tabBar);
connect(this, SIGNAL(tabCloseRequested(int)), SLOT(closeDatabase(int)));
connect(this, SIGNAL(currentChanged(int)), SLOT(emitActivateDatabaseChanged()));
connect(this, SIGNAL(activateDatabaseChanged(DatabaseWidget*)), m_dbWidgetSateSync, SLOT(setActive(DatabaseWidget*)));
connect(autoType(), SIGNAL(globalShortcutTriggered()), SLOT(performGlobalAutoType()));
}
@ -189,7 +193,7 @@ bool DatabaseTabWidget::closeDatabase(Database* db)
if (dbName.right(1) == "*") {
dbName.chop(1);
}
if (dbStruct.dbWidget->currentMode() == DatabaseWidget::EditMode && db->hasKey()) {
if (dbStruct.dbWidget->isInEditMode() && db->hasKey()) {
QMessageBox::StandardButton result =
MessageBox::question(
this, tr("Close?"),
@ -503,7 +507,7 @@ DatabaseWidget* DatabaseTabWidget::currentDatabaseWidget()
}
}
bool DatabaseTabWidget::hasLockableDatabases()
bool DatabaseTabWidget::hasLockableDatabases() const
{
QHashIterator<Database*, DatabaseManagerStruct> i(m_dbList);
while (i.hasNext()) {
@ -584,6 +588,11 @@ void DatabaseTabWidget::changeDatabase(Database* newDb)
connectDatabase(newDb, oldDb);
}
void DatabaseTabWidget::emitActivateDatabaseChanged()
{
Q_EMIT activateDatabaseChanged(currentDatabaseWidget());
}
void DatabaseTabWidget::connectDatabase(Database* newDb, Database* oldDb)
{
if (oldDb) {

View file

@ -25,6 +25,7 @@
#include "gui/DatabaseWidget.h"
class DatabaseWidget;
class DatabaseWidgetStateSync;
class DatabaseOpenWidget;
class QFile;
@ -53,7 +54,7 @@ public:
void openDatabase(const QString& fileName, const QString& pw = QString(),
const QString& keyFile = QString());
DatabaseWidget* currentDatabaseWidget();
bool hasLockableDatabases();
bool hasLockableDatabases() const;
static const int LastDatabasesCount;
@ -75,6 +76,7 @@ public Q_SLOTS:
Q_SIGNALS:
void tabNameChanged();
void databaseWithFileClosed(QString filePath);
void activateDatabaseChanged(DatabaseWidget* dbWidget);
private Q_SLOTS:
void updateTabName(Database* db);
@ -83,6 +85,7 @@ private Q_SLOTS:
void modified();
void toggleTabbar();
void changeDatabase(Database* newDb);
void emitActivateDatabaseChanged();
private:
void saveDatabase(Database* db);
@ -99,6 +102,7 @@ private:
KeePass2Writer m_writer;
QHash<Database*, DatabaseManagerStruct> m_dbList;
DatabaseWidgetStateSync* m_dbWidgetSateSync;
};
#endif // KEEPASSX_DATABASETABWIDGET_H

View file

@ -30,6 +30,7 @@
#include "autotype/AutoType.h"
#include "core/Config.h"
#include "core/EntrySearcher.h"
#include "core/FilePath.h"
#include "core/Group.h"
#include "core/Metadata.h"
@ -63,12 +64,13 @@ DatabaseWidget::DatabaseWidget(Database* db, QWidget* parent)
m_mainWidget = new QWidget(this);
QLayout* layout = new QHBoxLayout(m_mainWidget);
QSplitter* splitter = new QSplitter(m_mainWidget);
m_splitter = new QSplitter(m_mainWidget);
m_splitter->setChildrenCollapsible(false);
QWidget* rightHandSideWidget = new QWidget(splitter);
QWidget* rightHandSideWidget = new QWidget(m_splitter);
m_searchWidget->setParent(rightHandSideWidget);
m_groupView = new GroupView(db, splitter);
m_groupView = new GroupView(db, m_splitter);
m_groupView->setObjectName("groupView");
m_groupView->setContextMenuPolicy(Qt::CustomContextMenu);
connect(m_groupView, SIGNAL(customContextMenuRequested(QPoint)),
@ -81,14 +83,6 @@ DatabaseWidget::DatabaseWidget(Database* db, QWidget* parent)
connect(m_entryView, SIGNAL(customContextMenuRequested(QPoint)),
SLOT(emitEntryContextMenuRequested(QPoint)));
QSizePolicy policy;
policy = m_groupView->sizePolicy();
policy.setHorizontalStretch(30);
m_groupView->setSizePolicy(policy);
policy = rightHandSideWidget->sizePolicy();
policy.setHorizontalStretch(70);
rightHandSideWidget->setSizePolicy(policy);
QAction* closeAction = new QAction(m_searchWidget);
QIcon closeIcon = filePath()->icon("actions", "dialog-close");
closeAction->setIcon(closeIcon);
@ -104,10 +98,17 @@ DatabaseWidget::DatabaseWidget(Database* db, QWidget* parent)
rightHandSideWidget->setLayout(vLayout);
splitter->addWidget(m_groupView);
splitter->addWidget(rightHandSideWidget);
setTabOrder(m_searchUi->searchRootRadioButton, m_entryView);
setTabOrder(m_entryView, m_groupView);
setTabOrder(m_groupView, m_searchWidget);
layout->addWidget(splitter);
m_splitter->addWidget(m_groupView);
m_splitter->addWidget(rightHandSideWidget);
m_splitter->setStretchFactor(0, 30);
m_splitter->setStretchFactor(1, 70);
layout->addWidget(m_splitter);
m_mainWidget->setLayout(layout);
m_editEntryWidget = new EditEntryWidget();
@ -139,6 +140,8 @@ DatabaseWidget::DatabaseWidget(Database* db, QWidget* parent)
addWidget(m_keepass1OpenWidget);
addWidget(m_unlockDatabaseWidget);
connect(m_splitter, SIGNAL(splitterMoved(int,int)), SIGNAL(splitterSizesChanged()));
connect(m_entryView->header(), SIGNAL(sectionResized(int,int,int)), SIGNAL(entryColumnSizesChanged()));
connect(m_groupView, SIGNAL(groupChanged(Group*)), this, SLOT(clearLastGroup(Group*)));
connect(m_groupView, SIGNAL(groupChanged(Group*)), SIGNAL(groupChanged()));
connect(m_groupView, SIGNAL(groupChanged(Group*)), m_entryView, SLOT(setGroup(Group*)));
@ -171,7 +174,7 @@ DatabaseWidget::~DatabaseWidget()
{
}
DatabaseWidget::Mode DatabaseWidget::currentMode()
DatabaseWidget::Mode DatabaseWidget::currentMode() const
{
if (currentWidget() == Q_NULLPTR) {
return DatabaseWidget::None;
@ -187,21 +190,56 @@ DatabaseWidget::Mode DatabaseWidget::currentMode()
}
}
bool DatabaseWidget::isInEditMode() const
{
if (currentMode() == DatabaseWidget::LockedMode) {
return m_widgetBeforeLock != Q_NULLPTR
&& m_widgetBeforeLock != m_mainWidget
&& m_widgetBeforeLock != m_unlockDatabaseWidget;
}
else {
return currentMode() == DatabaseWidget::EditMode;
}
}
QList<int> DatabaseWidget::splitterSizes() const
{
return m_splitter->sizes();
}
void DatabaseWidget::setSplitterSizes(const QList<int>& sizes)
{
m_splitter->setSizes(sizes);
}
QList<int> DatabaseWidget::entryHeaderViewSizes() const
{
QList<int> sizes;
for (int i = 0; i < m_entryView->header()->count(); i++) {
sizes.append(m_entryView->header()->sectionSize(i));
}
return sizes;
}
void DatabaseWidget::setEntryViewHeaderSizes(const QList<int>& sizes)
{
if (sizes.size() != m_entryView->header()->count()) {
Q_ASSERT(false);
return;
}
for (int i = 0; i < sizes.size(); i++) {
m_entryView->header()->resizeSection(i, sizes[i]);
}
}
void DatabaseWidget::emitCurrentModeChanged()
{
Q_EMIT currentModeChanged(currentMode());
}
GroupView* DatabaseWidget::groupView()
{
return m_groupView;
}
EntryView* DatabaseWidget::entryView()
{
return m_entryView;
}
Database* DatabaseWidget::database()
{
return m_db;
@ -298,8 +336,7 @@ void DatabaseWidget::deleteEntries()
if (selected.size() > 1) {
QMessageBox::StandardButton result = MessageBox::question(
this, tr("Move entries to recycle bin?"),
tr("Do you really want to move %1 entries to the recycle bin?")
.arg(selected.size()),
tr("Do you really want to move %n entry(s) to the recycle bin?", 0, selected.size()),
QMessageBox::Yes | QMessageBox::No);
if (result == QMessageBox::No) {
return;
@ -431,7 +468,7 @@ void DatabaseWidget::createGroup()
void DatabaseWidget::deleteGroup()
{
Group* currentGroup = m_groupView->currentGroup();
if (!currentGroup || !canDeleteCurrentGoup()) {
if (!currentGroup || !canDeleteCurrentGroup()) {
Q_ASSERT(false);
return;
}
@ -601,7 +638,7 @@ void DatabaseWidget::unlockDatabase(bool accepted)
Q_ASSERT(accepted);
Q_UNUSED(accepted);
setCurrentWidget(widgetBeforeLock);
setCurrentWidget(m_widgetBeforeLock);
Q_EMIT unlockedDatabase();
}
@ -673,8 +710,16 @@ void DatabaseWidget::switchToImportKeepass1(const QString& fileName)
void DatabaseWidget::toggleSearch()
{
if (m_entryView->inEntryListMode()) {
closeSearch();
if (isInSearchMode()) {
if (m_searchUi->searchEdit->hasFocus()) {
closeSearch();
}
else {
m_searchUi->searchEdit->selectAll();
m_searchUi->searchEdit->setFocus();
// make sure the search action is checked again
emitCurrentModeChanged();
}
}
else {
showSearch();
@ -684,11 +729,19 @@ void DatabaseWidget::toggleSearch()
void DatabaseWidget::closeSearch()
{
Q_ASSERT(m_lastGroup);
Q_EMIT listModeAboutToActivate();
m_groupView->setCurrentGroup(m_lastGroup);
m_searchTimer->stop();
Q_EMIT listModeActivated();
}
void DatabaseWidget::showSearch()
{
Q_EMIT searchModeAboutToActivate();
m_searchUi->searchEdit->blockSignals(true);
m_searchUi->searchEdit->clear();
m_searchUi->searchEdit->blockSignals(false);
@ -722,6 +775,8 @@ void DatabaseWidget::showSearch()
m_searchWidget->show();
search();
m_searchUi->searchEdit->setFocus();
Q_EMIT searchModeActivated();
}
void DatabaseWidget::search()
@ -747,8 +802,8 @@ void DatabaseWidget::search()
else {
sensitivity = Qt::CaseInsensitive;
}
QList<Entry*> searchResult = searchGroup->search(m_searchUi->searchEdit->text(), sensitivity);
QList<Entry*> searchResult = EntrySearcher().search(m_searchUi->searchEdit->text(), searchGroup, sensitivity);
m_entryView->setEntryList(searchResult);
}
@ -779,19 +834,19 @@ void DatabaseWidget::emitEntryContextMenuRequested(const QPoint& pos)
Q_EMIT entryContextMenuRequested(m_entryView->viewport()->mapToGlobal(pos));
}
bool DatabaseWidget::dbHasKey()
bool DatabaseWidget::dbHasKey() const
{
return m_db->hasKey();
}
bool DatabaseWidget::canDeleteCurrentGoup()
bool DatabaseWidget::canDeleteCurrentGroup() const
{
bool isRootGroup = m_db->rootGroup() == m_groupView->currentGroup();
bool isRecycleBin = m_db->metadata()->recycleBin() == m_groupView->currentGroup();
return !isRootGroup && !isRecycleBin;
}
bool DatabaseWidget::isInSearchMode()
bool DatabaseWidget::isInSearchMode() const
{
return m_entryView->inEntryListMode();
}
@ -808,7 +863,7 @@ void DatabaseWidget::lock()
{
Q_ASSERT(currentMode() != DatabaseWidget::LockedMode);
widgetBeforeLock = currentWidget();
m_widgetBeforeLock = currentWidget();
m_unlockDatabaseWidget->load(m_filename, m_db);
setCurrentWidget(m_unlockDatabaseWidget);
}
@ -839,3 +894,23 @@ void DatabaseWidget::databaseModifedExternally()
delete oldDb;
}
}
int DatabaseWidget::numberOfSelectedEntries() const
{
return m_entryView->numberOfSelectedEntries();
}
QStringList DatabaseWidget::customEntryAttributes() const
{
Entry* entry = m_entryView->currentEntry();
if (!entry) {
return QStringList();
}
return entry->attributes()->customKeys();
}
bool DatabaseWidget::isGroupSelected() const
{
return m_groupView->currentGroup() != Q_NULLPTR;
}

View file

@ -39,6 +39,7 @@ class GroupView;
class KeePass1OpenWidget;
class QFile;
class QMenu;
class QSplitter;
class UnlockDatabaseWidget;
namespace Ui {
@ -60,18 +61,24 @@ public:
explicit DatabaseWidget(Database* db, QWidget* parent = Q_NULLPTR);
~DatabaseWidget();
GroupView* groupView();
EntryView* entryView();
Database* database();
bool dbHasKey();
bool canDeleteCurrentGoup();
bool isInSearchMode();
bool dbHasKey() const;
bool canDeleteCurrentGroup() const;
bool isInSearchMode() const;
int addWidget(QWidget* w);
void setCurrentIndex(int index);
void setCurrentWidget(QWidget* widget);
DatabaseWidget::Mode currentMode();
DatabaseWidget::Mode currentMode() const;
void lock();
void updateFilename(const QString& filename);
int numberOfSelectedEntries() const;
QStringList customEntryAttributes() const;
bool isGroupSelected() const;
bool isInEditMode() const;
QList<int> splitterSizes() const;
void setSplitterSizes(const QList<int>& sizes);
QList<int> entryHeaderViewSizes() const;
void setEntryViewHeaderSizes(const QList<int>& sizes);
Q_SIGNALS:
void closeRequest();
@ -82,6 +89,12 @@ Q_SIGNALS:
void groupContextMenuRequested(const QPoint& globalPos);
void entryContextMenuRequested(const QPoint& globalPos);
void unlockedDatabase();
void listModeAboutToActivate();
void listModeActivated();
void searchModeAboutToActivate();
void searchModeActivated();
void splitterSizesChanged();
void entryColumnSizesChanged();
public Q_SLOTS:
void createEntry();
@ -106,8 +119,6 @@ public Q_SLOTS:
void switchToOpenDatabase(const QString& fileName, const QString& password, const QString& keyFile);
void switchToImportKeepass1(const QString& fileName);
void toggleSearch();
void emitGroupContextMenuRequested(const QPoint& pos);
void emitEntryContextMenuRequested(const QPoint& pos);
private Q_SLOTS:
void entryActivationSignalReceived(Entry* entry, EntryModel::ModelColumn column);
@ -117,6 +128,8 @@ private Q_SLOTS:
void switchToEntryEdit(Entry* entry);
void switchToEntryEdit(Entry* entry, bool create);
void switchToGroupEdit(Group* entry, bool create);
void emitGroupContextMenuRequested(const QPoint& pos);
void emitEntryContextMenuRequested(const QPoint& pos);
void updateMasterKey(bool accepted);
void openDatabase(bool accepted);
void databaseModifedExternally();
@ -145,6 +158,7 @@ private:
DatabaseOpenWidget* m_databaseOpenWidget;
KeePass1OpenWidget* m_keepass1OpenWidget;
UnlockDatabaseWidget* m_unlockDatabaseWidget;
QSplitter* m_splitter;
GroupView* m_groupView;
EntryView* m_entryView;
Group* m_newGroup;
@ -152,7 +166,7 @@ private:
Group* m_newParent;
Group* m_lastGroup;
QTimer* m_searchTimer;
QWidget* widgetBeforeLock;
QWidget* m_widgetBeforeLock;
QString m_filename;
FileSystemWatcher m_file_watcher;
};

View file

@ -0,0 +1,154 @@
/*
* Copyright (C) 2014 Felix Geyer <debfx@fobos.de>
* Copyright (C) 2014 Florian Geyer <blueice@fobos.de>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "DatabaseWidgetStateSync.h"
#include "core/Config.h"
DatabaseWidgetStateSync::DatabaseWidgetStateSync(QObject* parent)
: QObject(parent)
, m_activeDbWidget(Q_NULLPTR)
, m_blockUpdates(false)
{
m_splitterSizes = variantToIntList(config()->get("GUI/SplitterState"));
m_columnSizesList = variantToIntList(config()->get("GUI/EntryListColumnSizes"));
m_columnSizesSearch = variantToIntList(config()->get("GUI/EntrySearchColumnSizes"));
}
DatabaseWidgetStateSync::~DatabaseWidgetStateSync()
{
config()->set("GUI/SplitterState", intListToVariant(m_splitterSizes));
config()->set("GUI/EntryListColumnSizes", intListToVariant(m_columnSizesList));
config()->set("GUI/EntrySearchColumnSizes", intListToVariant(m_columnSizesSearch));
}
void DatabaseWidgetStateSync::setActive(DatabaseWidget* dbWidget)
{
if (m_activeDbWidget) {
disconnect(m_activeDbWidget, 0, this, 0);
}
m_activeDbWidget = dbWidget;
if (m_activeDbWidget) {
m_blockUpdates = true;
if (!m_splitterSizes.isEmpty()) {
m_activeDbWidget->setSplitterSizes(m_splitterSizes);
}
if (m_activeDbWidget->isGroupSelected()) {
restoreListView();
}
else {
restoreSearchView();
}
m_blockUpdates = false;
connect(m_activeDbWidget, SIGNAL(splitterSizesChanged()),
SLOT(updateSplitterSizes()));
connect(m_activeDbWidget, SIGNAL(entryColumnSizesChanged()),
SLOT(updateColumnSizes()));
connect(m_activeDbWidget, SIGNAL(listModeActivated()),
SLOT(restoreListView()));
connect(m_activeDbWidget, SIGNAL(searchModeActivated()),
SLOT(restoreSearchView()));
connect(m_activeDbWidget, SIGNAL(listModeAboutToActivate()),
SLOT(blockUpdates()));
connect(m_activeDbWidget, SIGNAL(searchModeAboutToActivate()),
SLOT(blockUpdates()));
}
}
void DatabaseWidgetStateSync::restoreListView()
{
if (!m_columnSizesList.isEmpty()) {
m_activeDbWidget->setEntryViewHeaderSizes(m_columnSizesList);
}
m_blockUpdates = false;
}
void DatabaseWidgetStateSync::restoreSearchView()
{
if (!m_columnSizesSearch.isEmpty()) {
m_activeDbWidget->setEntryViewHeaderSizes(m_columnSizesSearch);
}
m_blockUpdates = false;
}
void DatabaseWidgetStateSync::blockUpdates()
{
m_blockUpdates = true;
}
void DatabaseWidgetStateSync::updateSplitterSizes()
{
if (m_blockUpdates) {
return;
}
m_splitterSizes = m_activeDbWidget->splitterSizes();
}
void DatabaseWidgetStateSync::updateColumnSizes()
{
if (m_blockUpdates) {
return;
}
if (m_activeDbWidget->isGroupSelected()) {
m_columnSizesList = m_activeDbWidget->entryHeaderViewSizes();
}
else {
m_columnSizesSearch = m_activeDbWidget->entryHeaderViewSizes();
}
}
QList<int> DatabaseWidgetStateSync::variantToIntList(const QVariant& variant)
{
QVariantList list = variant.toList();
QList<int> result;
Q_FOREACH (const QVariant& var, list) {
bool ok;
int size = var.toInt(&ok);
if (ok) {
result.append(size);
}
else {
result.clear();
break;
}
}
return result;
}
QVariant DatabaseWidgetStateSync::intListToVariant(const QList<int>& list)
{
QVariantList result;
Q_FOREACH (int value, list) {
result.append(value);
}
return result;
}

View file

@ -0,0 +1,54 @@
/*
* Copyright (C) 2014 Felix Geyer <debfx@fobos.de>
* Copyright (C) 2014 Florian Geyer <blueice@fobos.de>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef KEEPASSX_HEADERVIEWSYNC_H
#define KEEPASSX_HEADERVIEWSYNC_H
#include "gui/DatabaseWidget.h"
class DatabaseWidgetStateSync : public QObject
{
Q_OBJECT
public:
explicit DatabaseWidgetStateSync(QObject* parent = Q_NULLPTR);
~DatabaseWidgetStateSync();
public Q_SLOTS:
void setActive(DatabaseWidget* dbWidget);
void restoreListView();
void restoreSearchView();
private Q_SLOTS:
void blockUpdates();
void updateSplitterSizes();
void updateColumnSizes();
private:
static QList<int> variantToIntList(const QVariant& variant);
static QVariant intListToVariant(const QList<int>& list);
DatabaseWidget* m_activeDbWidget;
bool m_blockUpdates;
QList<int> m_splitterSizes;
QList<int> m_columnSizesList;
QList<int> m_columnSizesSearch;
};
#endif // KEEPASSX_HEADERVIEWSYNC_H

View file

@ -194,8 +194,7 @@ void EditWidgetIcons::removeCustomIcon()
}
else {
MessageBox::information(this, tr("Can't delete icon!"),
tr("Can't delete icon. Still used by %1 items.")
.arg(iconUsedCount));
tr("Can't delete icon. Still used by %n item(s).", 0, iconUsedCount));
}
}
}

View file

@ -64,8 +64,8 @@ void KeePass1OpenWidget::openDatabase()
Q_EMIT editFinished(true);
}
else {
MessageBox::warning(this, tr("Error"), tr("Unable to open the database.\n%1")
.arg(reader.errorString()));
MessageBox::warning(this, tr("Error"), tr("Unable to open the database.").append("\n")
.append(reader.errorString()));
m_ui->editPassword->clear();
}
}

View file

@ -23,15 +23,11 @@
#include "autotype/AutoType.h"
#include "core/Config.h"
#include "core/Database.h"
#include "core/Entry.h"
#include "core/FilePath.h"
#include "core/InactivityTimer.h"
#include "core/Metadata.h"
#include "gui/AboutDialog.h"
#include "gui/DatabaseWidget.h"
#include "gui/entry/EntryView.h"
#include "gui/group/GroupView.h"
const QString MainWindow::BaseWindowTitle = "KeePassX";
@ -40,7 +36,9 @@ MainWindow::MainWindow()
{
m_ui->setupUi(this);
restoreGeometry(config()->get("window/Geometry").toByteArray());
m_countDefaultAttributes = m_ui->menuEntryCopyAttribute->actions().size();
restoreGeometry(config()->get("GUI/MainWindowGeometry").toByteArray());
setWindowIcon(filePath()->applicationIcon());
QAction* toggleViewAction = m_ui->toolBar->toggleViewAction();
@ -229,17 +227,16 @@ void MainWindow::updateCopyAttributesMenu()
return;
}
Entry* entry = dbWidget->entryView()->currentEntry();
if (!entry || !dbWidget->entryView()->isSingleEntrySelected()) {
if (!dbWidget->numberOfSelectedEntries() == 1) {
return;
}
QList<QAction*> actions = m_ui->menuEntryCopyAttribute->actions();
for (int i = EntryAttributes::DefaultAttributes.size() + 1; i < actions.size(); i++) {
for (int i = m_countDefaultAttributes + 1; i < actions.size(); i++) {
delete actions[i];
}
Q_FOREACH (const QString& key, entry->attributes()->customKeys()) {
Q_FOREACH (const QString& key, dbWidget->customEntryAttributes()) {
QAction* action = m_ui->menuEntryCopyAttribute->addAction(key);
m_copyAdditionalAttributeActions->addAction(action);
}
@ -276,9 +273,9 @@ void MainWindow::setMenuActionState(DatabaseWidget::Mode mode)
switch (mode) {
case DatabaseWidget::ViewMode: {
bool inSearch = dbWidget->isInSearchMode();
bool singleEntrySelected = dbWidget->entryView()->isSingleEntrySelected();
bool entriesSelected = !dbWidget->entryView()->selectionModel()->selectedRows().isEmpty();
bool groupSelected = dbWidget->groupView()->currentGroup();
bool singleEntrySelected = dbWidget->numberOfSelectedEntries() == 1;
bool entriesSelected = dbWidget->numberOfSelectedEntries() > 0;
bool groupSelected = dbWidget->isGroupSelected();
m_ui->actionEntryNew->setEnabled(!inSearch);
m_ui->actionEntryClone->setEnabled(singleEntrySelected && !inSearch);
@ -294,7 +291,7 @@ void MainWindow::setMenuActionState(DatabaseWidget::Mode mode)
m_ui->actionEntryOpenUrl->setEnabled(singleEntrySelected);
m_ui->actionGroupNew->setEnabled(groupSelected);
m_ui->actionGroupEdit->setEnabled(groupSelected);
m_ui->actionGroupDelete->setEnabled(groupSelected && dbWidget->canDeleteCurrentGoup());
m_ui->actionGroupDelete->setEnabled(groupSelected && dbWidget->canDeleteCurrentGroup());
m_ui->actionSearch->setEnabled(true);
// TODO: get checked state from db widget
m_ui->actionSearch->setChecked(inSearch);
@ -313,6 +310,11 @@ void MainWindow::setMenuActionState(DatabaseWidget::Mode mode)
Q_FOREACH (QAction* action, m_ui->menuGroups->actions()) {
action->setEnabled(false);
}
m_ui->actionEntryCopyTitle->setEnabled(false);
m_ui->actionEntryCopyUsername->setEnabled(false);
m_ui->actionEntryCopyPassword->setEnabled(false);
m_ui->actionEntryCopyURL->setEnabled(false);
m_ui->actionEntryCopyNotes->setEnabled(false);
m_ui->menuEntryCopyAttribute->setEnabled(false);
m_ui->actionSearch->setEnabled(false);
@ -335,6 +337,11 @@ void MainWindow::setMenuActionState(DatabaseWidget::Mode mode)
Q_FOREACH (QAction* action, m_ui->menuGroups->actions()) {
action->setEnabled(false);
}
m_ui->actionEntryCopyTitle->setEnabled(false);
m_ui->actionEntryCopyUsername->setEnabled(false);
m_ui->actionEntryCopyPassword->setEnabled(false);
m_ui->actionEntryCopyURL->setEnabled(false);
m_ui->actionEntryCopyNotes->setEnabled(false);
m_ui->menuEntryCopyAttribute->setEnabled(false);
m_ui->actionSearch->setEnabled(false);
@ -430,7 +437,7 @@ void MainWindow::closeEvent(QCloseEvent* event)
void MainWindow::saveWindowInformation()
{
config()->set("window/Geometry", saveGeometry());
config()->set("GUI/MainWindowGeometry", saveGeometry());
}
bool MainWindow::saveLastDatabases()

View file

@ -77,6 +77,7 @@ private:
QActionGroup* m_copyAdditionalAttributeActions;
QStringList m_openDatabases;
InactivityTimer* m_inactivityTimer;
int m_countDefaultAttributes;
Q_DISABLE_COPY(MainWindow)
};

View file

@ -100,7 +100,7 @@
<string>Upper Case Letters</string>
</property>
<property name="text">
<string>A-Z</string>
<string notr="true">A-Z</string>
</property>
<property name="checkable">
<bool>true</bool>
@ -116,7 +116,7 @@
<string>Lower Case Letters</string>
</property>
<property name="text">
<string>a-z</string>
<string notr="true">a-z</string>
</property>
<property name="checkable">
<bool>true</bool>
@ -132,7 +132,7 @@
<string>Numbers</string>
</property>
<property name="text">
<string>0-9</string>
<string notr="true">0-9</string>
</property>
<property name="checkable">
<bool>true</bool>
@ -148,7 +148,7 @@
<string>Special Characters</string>
</property>
<property name="text">
<string>/*_&amp; ...</string>
<string notr="true">/*_&amp; ...</string>
</property>
<property name="checkable">
<bool>true</bool>

View file

@ -11,7 +11,16 @@
</rect>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="margin">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="1">
@ -21,6 +30,9 @@
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QToolButton" name="closeSearchButton">
<property name="focusPolicy">
<enum>Qt::ClickFocus</enum>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
@ -38,7 +50,16 @@
<item row="1" column="1">
<widget class="QWidget" name="optionsWidget" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="margin">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>

View file

@ -21,6 +21,7 @@
#include "autotype/AutoType.h"
#include "core/Config.h"
#include "core/Translator.h"
SettingsWidget::SettingsWidget(QWidget* parent)
: EditWidget(parent)
@ -67,6 +68,16 @@ void SettingsWidget::loadSettings()
m_generalUi->autoSaveOnExitCheckBox->setChecked(config()->get("AutoSaveOnExit").toBool());
m_generalUi->minimizeOnCopyCheckBox->setChecked(config()->get("MinimizeOnCopy").toBool());
m_generalUi->useGroupIconOnEntryCreationCheckBox->setChecked(config()->get("UseGroupIconOnEntryCreation").toBool());
m_generalUi->autoTypeEntryTitleMatchCheckBox->setChecked(config()->get("AutoTypeEntryTitleMatch").toBool());
QList<QPair<QString, QString> > languages = Translator::availableLanguages();
for (int i = 0; i < languages.size(); i++) {
m_generalUi->languageComboBox->addItem(languages[i].second, languages[i].first);
}
int defaultIndex = m_generalUi->languageComboBox->findData(config()->get("GUI/Language"));
if (defaultIndex > 0) {
m_generalUi->languageComboBox->setCurrentIndex(defaultIndex);
}
if (autoType()->isAvailable()) {
m_globalAutoTypeKey = static_cast<Qt::Key>(config()->get("GlobalAutoTypeKey").toInt());
@ -102,6 +113,10 @@ void SettingsWidget::saveSettings()
config()->set("MinimizeOnCopy", m_generalUi->minimizeOnCopyCheckBox->isChecked());
config()->set("UseGroupIconOnEntryCreation",
m_generalUi->useGroupIconOnEntryCreationCheckBox->isChecked());
config()->set("AutoTypeEntryTitleMatch",
m_generalUi->autoTypeEntryTitleMatchCheckBox->isChecked());
int currentLangIndex = m_generalUi->languageComboBox->currentIndex();
config()->set("GUI/Language", m_generalUi->languageComboBox->itemData(currentLangIndex).toString());
if (autoType()->isAvailable()) {
config()->set("GlobalAutoTypeKey", m_generalUi->autoTypeShortcutWidget->key());
config()->set("GlobalAutoTypeModifiers",

View file

@ -7,10 +7,13 @@
<x>0</x>
<y>0</y>
<width>456</width>
<height>185</height>
<height>288</height>
</rect>
</property>
<layout class="QFormLayout" name="formLayout">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
</property>
<item row="0" column="0">
<widget class="QCheckBox" name="rememberLastDatabasesCheckBox">
<property name="text">
@ -21,6 +24,13 @@
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="openPreviousDatabasesOnStartupCheckBox">
<property name="text">
<string>Open previous databases on startup</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="modifiedExpandedChangedCheckBox">
<property name="text">
@ -31,13 +41,6 @@
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="autoSaveAfterEveryChangeCheckBox">
<property name="text">
<string>Automatically save after every change</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="autoSaveOnExitCheckBox">
<property name="text">
@ -45,20 +48,10 @@
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="autoTypeShortcutLabel">
<item row="4" column="0">
<widget class="QCheckBox" name="autoSaveAfterEveryChangeCheckBox">
<property name="text">
<string>Global Auto-Type shortcut</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="ShortcutWidget" name="autoTypeShortcutWidget"/>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="openPreviousDatabasesOnStartupCheckBox">
<property name="text">
<string>Open previous databases on startup</string>
<string>Automatically save after every change</string>
</property>
</widget>
</item>
@ -76,6 +69,33 @@
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="autoTypeShortcutLabel">
<property name="text">
<string>Global Auto-Type shortcut</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="ShortcutWidget" name="autoTypeShortcutWidget"/>
</item>
<item row="8" column="0">
<widget class="QCheckBox" name="autoTypeEntryTitleMatchCheckBox">
<property name="text">
<string>Use entry title to match windows for global auto-type</string>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QLabel" name="languageLabel">
<property name="text">
<string>Language</string>
</property>
</widget>
</item>
<item row="9" column="1">
<widget class="QComboBox" name="languageComboBox"/>
</item>
</layout>
</widget>
<customwidgets>

View file

@ -590,14 +590,14 @@ void EditEntryWidget::insertAttachment()
QFile file(filename);
if (!file.open(QIODevice::ReadOnly)) {
MessageBox::warning(this, tr("Error"),
tr("Unable to open file:\n").append(file.errorString()));
tr("Unable to open file").append(":\n").append(file.errorString()));
return;
}
QByteArray data;
if (!Tools::readAllFromDevice(&file, data)) {
MessageBox::warning(this, tr("Error"),
tr("Unable to open file:\n").append(file.errorString()));
tr("Unable to open file").append(":\n").append(file.errorString()));
return;
}
@ -783,13 +783,13 @@ QMenu* EditEntryWidget::createPresetsMenu()
QMenu* expirePresetsMenu = new QMenu(this);
expirePresetsMenu->addAction(tr("Tomorrow"))->setData(QVariant::fromValue(TimeDelta::fromDays(1)));
expirePresetsMenu->addSeparator();
expirePresetsMenu->addAction(tr("1 week"))->setData(QVariant::fromValue(TimeDelta::fromDays(7)));
expirePresetsMenu->addAction(tr("2 weeks"))->setData(QVariant::fromValue(TimeDelta::fromDays(14)));
expirePresetsMenu->addAction(tr("3 weeks"))->setData(QVariant::fromValue(TimeDelta::fromDays(21)));
expirePresetsMenu->addAction(tr("%n week(s)", 0, 1))->setData(QVariant::fromValue(TimeDelta::fromDays(7)));
expirePresetsMenu->addAction(tr("%n week(s)", 0, 2))->setData(QVariant::fromValue(TimeDelta::fromDays(14)));
expirePresetsMenu->addAction(tr("%n week(s)", 0, 3))->setData(QVariant::fromValue(TimeDelta::fromDays(21)));
expirePresetsMenu->addSeparator();
expirePresetsMenu->addAction(tr("1 month"))->setData(QVariant::fromValue(TimeDelta::fromMonths(1)));
expirePresetsMenu->addAction(tr("3 months"))->setData(QVariant::fromValue(TimeDelta::fromMonths(3)));
expirePresetsMenu->addAction(tr("6 months"))->setData(QVariant::fromValue(TimeDelta::fromMonths(6)));
expirePresetsMenu->addAction(tr("%n month(s)", 0, 1))->setData(QVariant::fromValue(TimeDelta::fromMonths(1)));
expirePresetsMenu->addAction(tr("%n month(s)", 0, 3))->setData(QVariant::fromValue(TimeDelta::fromMonths(3)));
expirePresetsMenu->addAction(tr("%n month(s)", 0, 6))->setData(QVariant::fromValue(TimeDelta::fromMonths(6)));
expirePresetsMenu->addSeparator();
expirePresetsMenu->addAction(tr("1 year"))->setData(QVariant::fromValue(TimeDelta::fromYears(1)));
return expirePresetsMenu;

View file

@ -17,6 +17,7 @@
#include "EntryView.h"
#include <QHeaderView>
#include <QKeyEvent>
#include "gui/SortFilterHideProxyModel.h"
@ -40,6 +41,7 @@ EntryView::EntryView(QWidget* parent)
setDragEnabled(true);
setSortingEnabled(true);
setSelectionMode(QAbstractItemView::ExtendedSelection);
header()->setDefaultSectionSize(150);
// QAbstractItemView::startDrag() uses this property as the default drag action
setDefaultDropAction(Qt::MoveAction);
@ -62,13 +64,24 @@ void EntryView::keyPressEvent(QKeyEvent* event)
void EntryView::setGroup(Group* group)
{
m_model->setGroup(group);
Q_EMIT entrySelectionChanged();
setFirstEntryActive();
}
void EntryView::setEntryList(const QList<Entry*>& entries)
{
m_model->setEntryList(entries);
Q_EMIT entrySelectionChanged();
setFirstEntryActive();
}
void EntryView::setFirstEntryActive()
{
if(m_model->rowCount() > 0) {
QModelIndex index = m_sortModel->mapToSource(m_sortModel->index(0, 0));
setCurrentEntry(m_model->entryFromIndex(index));
}
else {
Q_EMIT entrySelectionChanged();
}
}
bool EntryView::inEntryListMode()
@ -100,9 +113,9 @@ Entry* EntryView::currentEntry()
}
}
bool EntryView::isSingleEntrySelected()
int EntryView::numberOfSelectedEntries()
{
return (selectionModel()->selectedRows().size() == 1);
return selectionModel()->selectedRows().size();
}
void EntryView::setCurrentEntry(Entry* entry)

View file

@ -37,11 +37,12 @@ public:
explicit EntryView(QWidget* parent = Q_NULLPTR);
void setModel(QAbstractItemModel* model) Q_DECL_OVERRIDE;
Entry* currentEntry();
bool isSingleEntrySelected();
void setCurrentEntry(Entry* entry);
Entry* entryFromIndex(const QModelIndex& index);
void setEntryList(const QList<Entry*>& entries);
bool inEntryListMode();
int numberOfSelectedEntries();
void setFirstEntryActive();
public Q_SLOTS:
void setGroup(Group* group);

View file

@ -21,6 +21,7 @@
#include "core/Config.h"
#include "core/qcommandlineparser.h"
#include "core/Tools.h"
#include "core/Translator.h"
#include "crypto/Crypto.h"
#include "gui/Application.h"
#include "gui/MainWindow.h"
@ -66,6 +67,8 @@ int main(int argc, char** argv)
Config::createConfigFromFile(parser.value(configOption));
}
Translator::installTranslator();
#ifdef Q_OS_MAC
// Don't show menu icons on OSX
QApplication::setAttribute(Qt::AA_DontShowIconsInMenus);