Support copying username and password to the clipboard.

This commit is contained in:
Felix Geyer 2012-05-26 16:20:32 +02:00
parent bbd039e487
commit f43ad8d062
11 changed files with 227 additions and 5 deletions

View File

@ -138,7 +138,12 @@ if(WITH_TESTS)
enable_testing() enable_testing()
endif(WITH_TESTS) endif(WITH_TESTS)
find_package(Qt4 4.6.0 REQUIRED QtCore QtGui QtTest) set(QT_REQUIRED_MODULES QtCore QtGui QtTest)
if(UNIX AND NOT APPLE)
set(QT_REQUIRED_MODULES ${QT_REQUIRED_MODULES} QtDBus)
endif()
find_package(Qt4 4.6.0 REQUIRED ${QT_REQUIRED_MODULES})
add_definitions(${QT_DEFINITIONS} -DQT_CORE_LIB -DQT_GUI_LIB) add_definitions(${QT_DEFINITIONS} -DQT_CORE_LIB -DQT_GUI_LIB)
set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS_DEBUG QT_DEBUG) set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS_DEBUG QT_DEBUG)
set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS_RELEASE QT_NO_DEBUG) set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS_RELEASE QT_NO_DEBUG)

View File

@ -54,6 +54,7 @@ set(keepassx_SOURCES
gui/AboutDialog.cpp gui/AboutDialog.cpp
gui/Application.cpp gui/Application.cpp
gui/ChangeMasterKeyWidget.cpp gui/ChangeMasterKeyWidget.cpp
gui/Clipboard.cpp
gui/DatabaseOpenDialog.cpp gui/DatabaseOpenDialog.cpp
gui/DatabaseSettingsWidget.cpp gui/DatabaseSettingsWidget.cpp
gui/DatabaseTabWidget.cpp gui/DatabaseTabWidget.cpp
@ -96,6 +97,7 @@ set(keepassx_MOC
gui/AboutDialog.h gui/AboutDialog.h
gui/Application.h gui/Application.h
gui/ChangeMasterKeyWidget.h gui/ChangeMasterKeyWidget.h
gui/Clipboard.h
gui/DatabaseOpenDialog.h gui/DatabaseOpenDialog.h
gui/DatabaseSettingsWidget.h gui/DatabaseSettingsWidget.h
gui/DatabaseTabWidget.h gui/DatabaseTabWidget.h
@ -154,6 +156,10 @@ target_link_libraries(${PROGNAME}
${GCRYPT_LIBRARIES} ${GCRYPT_LIBRARIES}
${ZLIB_LIBRARIES}) ${ZLIB_LIBRARIES})
if(UNIX AND NOT APPLE)
target_link_libraries(${PROGNAME} ${QT_QTDBUS_LIBRARY})
endif()
if(APPLE) if(APPLE)
configure_file(${CMAKE_SOURCE_DIR}/share/macosx/Info.plist.cmake ${CMAKE_CURRENT_BINARY_DIR}/Info.plist) configure_file(${CMAKE_SOURCE_DIR}/share/macosx/Info.plist.cmake ${CMAKE_CURRENT_BINARY_DIR}/Info.plist)
set_target_properties(${PROGNAME} PROPERTIES set_target_properties(${PROGNAME} PROPERTIES

82
src/gui/Clipboard.cpp Normal file
View File

@ -0,0 +1,82 @@
/*
* Copyright (C) 2012 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 "Clipboard.h"
#include <QtCore/QTimer>
#include <QtGui/QApplication>
#include <QtGui/QClipboard>
#ifdef Q_WS_X11
#include <QtDBus/QDBusConnection>
#include <QtDBus/QDBusMessage>
#endif
Clipboard::Clipboard(QObject* parent)
: QObject(parent)
, m_timer(new QTimer(this))
{
m_timer->setSingleShot(true);
connect(m_timer, SIGNAL(timeout()), SLOT(clearClipboard()));
}
Clipboard::~Clipboard()
{
if (m_timer->isActive()) {
clearClipboard();
}
}
void Clipboard::setText(const QString& text, int clearTimeout)
{
QClipboard* clipboard = QApplication::clipboard();
clipboard->setText(text, QClipboard::Clipboard);
if (clipboard->supportsSelection()) {
clipboard->setText(text, QClipboard::Selection);
}
if (clearTimeout > 0) {
m_timer->start(clearTimeout);
}
}
void Clipboard::clearClipboard()
{
QClipboard* clipboard = QApplication::clipboard();
clipboard->clear(QClipboard::Clipboard);
if (clipboard->supportsSelection()) {
clipboard->clear(QClipboard::Selection);
}
#ifdef Q_WS_X11
QDBusMessage message = QDBusMessage::createMethodCall("org.kde.klipper", "/klipper", "", "clearClipboardHistory");
QDBusConnection::sessionBus().send(message);
#endif
}
Clipboard* clipboard()
{
static Clipboard* instance(0);
if (!instance) {
instance = new Clipboard(qApp);
}
return instance;
}

46
src/gui/Clipboard.h Normal file
View File

@ -0,0 +1,46 @@
/*
* Copyright (C) 2012 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_CLIPBOARD_H
#define KEEPASSX_CLIPBOARD_H
#include <QtCore/QObject>
class QTimer;
class Clipboard : public QObject
{
Q_OBJECT
public:
~Clipboard();
void setText(const QString& text, int clearTimeout = 0);
private:
Clipboard(QObject* parent = 0);
QTimer* m_timer;
private Q_SLOTS:
void clearClipboard();
friend Clipboard* clipboard();
};
Clipboard* clipboard();
#endif // KEEPASSX_CLIPBOARD_H

View File

@ -349,6 +349,16 @@ void DatabaseTabWidget::deleteEntry()
currentDatabaseWidget()->deleteEntry(); currentDatabaseWidget()->deleteEntry();
} }
void DatabaseTabWidget::copyUsername()
{
currentDatabaseWidget()->copyUsername();
}
void DatabaseTabWidget::copyPassword()
{
currentDatabaseWidget()->copyPassword();
}
void DatabaseTabWidget::createGroup() void DatabaseTabWidget::createGroup()
{ {
currentDatabaseWidget()->createGroup(); currentDatabaseWidget()->createGroup();

View File

@ -66,6 +66,8 @@ public Q_SLOTS:
void cloneEntry(); void cloneEntry();
void editEntry(); void editEntry();
void deleteEntry(); void deleteEntry();
void copyUsername();
void copyPassword();
void createGroup(); void createGroup();
void editGroup(); void editGroup();
void deleteGroup(); void deleteGroup();

View File

@ -31,6 +31,7 @@
#include "core/Metadata.h" #include "core/Metadata.h"
#include "core/Tools.h" #include "core/Tools.h"
#include "gui/ChangeMasterKeyWidget.h" #include "gui/ChangeMasterKeyWidget.h"
#include "gui/Clipboard.h"
#include "gui/DatabaseSettingsWidget.h" #include "gui/DatabaseSettingsWidget.h"
#include "gui/entry/EditEntryWidget.h" #include "gui/entry/EditEntryWidget.h"
#include "gui/entry/EntryView.h" #include "gui/entry/EntryView.h"
@ -122,6 +123,12 @@ DatabaseWidget::DatabaseWidget(Database* db, QWidget* parent)
m_actionEntryEditView->setEnabled(false); m_actionEntryEditView->setEnabled(false);
m_actionEntryDelete = m_menuEntry->addAction(tr("Delete entry"), this, SLOT(deleteEntry())); m_actionEntryDelete = m_menuEntry->addAction(tr("Delete entry"), this, SLOT(deleteEntry()));
m_actionEntryDelete->setEnabled(false); m_actionEntryDelete->setEnabled(false);
m_actionEntryCopyUsername = m_menuEntry->addAction(tr("Copy username to clipboard"), this,
SLOT(copyUsername()), Qt::CTRL + Qt::Key_B);
m_actionEntryCopyUsername->setEnabled(false);
m_actionEntryCopyPassword = m_menuEntry->addAction(tr("Copy password to clipboard"), this,
SLOT(copyPassword()), Qt::CTRL + Qt::Key_C);
m_actionEntryCopyPassword->setEnabled(false);
m_actionGroupNew = m_menuGroup->addAction(tr("Add new group"), this, SLOT(createGroup())); m_actionGroupNew = m_menuGroup->addAction(tr("Add new group"), this, SLOT(createGroup()));
m_actionGroupEdit = m_menuGroup->addAction(tr("Edit group"), this, SLOT(switchToGroupEdit())); m_actionGroupEdit = m_menuGroup->addAction(tr("Edit group"), this, SLOT(switchToGroupEdit()));
@ -238,6 +245,30 @@ void DatabaseWidget::deleteEntry()
} }
} }
void DatabaseWidget::copyUsername()
{
Entry* currentEntry = m_entryView->currentEntry();
if (!currentEntry) {
Q_ASSERT(false);
return;
}
// TODO: set clearTimeout
clipboard()->setText(currentEntry->username());
}
void DatabaseWidget::copyPassword()
{
Entry* currentEntry = m_entryView->currentEntry();
if (!currentEntry) {
Q_ASSERT(false);
return;
}
// TODO: set clearTimeout
clipboard()->setText(currentEntry->password());
}
void DatabaseWidget::createGroup() void DatabaseWidget::createGroup()
{ {
if (!m_groupView->currentGroup()) { if (!m_groupView->currentGroup()) {
@ -493,6 +524,8 @@ void DatabaseWidget::updateEntryActions()
m_actionEntryClone->setEnabled(singleEntrySelected && !inSearch); m_actionEntryClone->setEnabled(singleEntrySelected && !inSearch);
m_actionEntryEditView->setEnabled(singleEntrySelected); m_actionEntryEditView->setEnabled(singleEntrySelected);
m_actionEntryDelete->setEnabled(singleEntrySelected); m_actionEntryDelete->setEnabled(singleEntrySelected);
m_actionEntryCopyUsername->setEnabled(singleEntrySelected);
m_actionEntryCopyPassword->setEnabled(singleEntrySelected);
} }
void DatabaseWidget::showGroupContextMenu(const QPoint& pos) void DatabaseWidget::showGroupContextMenu(const QPoint& pos)

View File

@ -66,6 +66,8 @@ public Q_SLOTS:
void createEntry(); void createEntry();
void cloneEntry(); void cloneEntry();
void deleteEntry(); void deleteEntry();
void copyUsername();
void copyPassword();
void createGroup(); void createGroup();
void deleteGroup(); void deleteGroup();
void switchToEntryEdit(); void switchToEntryEdit();
@ -123,6 +125,8 @@ private:
QAction* m_actionEntryClone; QAction* m_actionEntryClone;
QAction* m_actionEntryEditView; QAction* m_actionEntryEditView;
QAction* m_actionEntryDelete; QAction* m_actionEntryDelete;
QAction* m_actionEntryCopyUsername;
QAction* m_actionEntryCopyPassword;
}; };
#endif // KEEPASSX_DATABASEWIDGET_H #endif // KEEPASSX_DATABASEWIDGET_H

View File

@ -41,6 +41,8 @@ MainWindow::MainWindow()
setShortcut(m_ui->actionDatabaseClose, QKeySequence::Close, Qt::CTRL + Qt::Key_W); setShortcut(m_ui->actionDatabaseClose, QKeySequence::Close, Qt::CTRL + Qt::Key_W);
setShortcut(m_ui->actionQuit, QKeySequence::Quit, Qt::CTRL + Qt::Key_Q); setShortcut(m_ui->actionQuit, QKeySequence::Quit, Qt::CTRL + Qt::Key_Q);
setShortcut(m_ui->actionSearch, QKeySequence::Find, Qt::CTRL + Qt::Key_F); setShortcut(m_ui->actionSearch, QKeySequence::Find, Qt::CTRL + Qt::Key_F);
m_ui->actionEntryCopyUsername->setShortcut(Qt::CTRL + Qt::Key_B);
m_ui->actionEntryCopyPassword->setShortcut(Qt::CTRL + Qt::Key_C);
connect(m_ui->tabWidget, SIGNAL(entrySelectionChanged(bool)), connect(m_ui->tabWidget, SIGNAL(entrySelectionChanged(bool)),
SLOT(setMenuActionState())); SLOT(setMenuActionState()));
@ -78,6 +80,10 @@ MainWindow::MainWindow()
SLOT(editEntry())); SLOT(editEntry()));
connect(m_ui->actionEntryDelete, SIGNAL(triggered()), m_ui->tabWidget, connect(m_ui->actionEntryDelete, SIGNAL(triggered()), m_ui->tabWidget,
SLOT(deleteEntry())); SLOT(deleteEntry()));
connect(m_ui->actionEntryCopyUsername, SIGNAL(triggered()), m_ui->tabWidget,
SLOT(copyUsername()));
connect(m_ui->actionEntryCopyPassword, SIGNAL(triggered()), m_ui->tabWidget,
SLOT(copyPassword()));
connect(m_ui->actionGroupNew, SIGNAL(triggered()), m_ui->tabWidget, connect(m_ui->actionGroupNew, SIGNAL(triggered()), m_ui->tabWidget,
SLOT(createGroup())); SLOT(createGroup()));
@ -121,6 +127,8 @@ void MainWindow::setMenuActionState(DatabaseWidget::Mode mode)
m_ui->actionEntryClone->setEnabled(!inSearch && singleEntry); m_ui->actionEntryClone->setEnabled(!inSearch && singleEntry);
m_ui->actionEntryEdit->setEnabled(singleEntry); m_ui->actionEntryEdit->setEnabled(singleEntry);
m_ui->actionEntryDelete->setEnabled(singleEntry); m_ui->actionEntryDelete->setEnabled(singleEntry);
m_ui->actionEntryCopyUsername->setEnabled(singleEntry);
m_ui->actionEntryCopyPassword->setEnabled(singleEntry);
m_ui->actionGroupNew->setEnabled(!inSearch); m_ui->actionGroupNew->setEnabled(!inSearch);
m_ui->actionGroupEdit->setEnabled(!inSearch); m_ui->actionGroupEdit->setEnabled(!inSearch);
m_ui->actionGroupDelete->setEnabled(!inSearch && dbWidget->canDeleteCurrentGoup()); m_ui->actionGroupDelete->setEnabled(!inSearch && dbWidget->canDeleteCurrentGoup());
@ -134,11 +142,13 @@ void MainWindow::setMenuActionState(DatabaseWidget::Mode mode)
} }
case DatabaseWidget::EditMode: case DatabaseWidget::EditMode:
m_ui->actionEntryNew->setEnabled(false); m_ui->actionEntryNew->setEnabled(false);
m_ui->actionGroupNew->setEnabled(false);
m_ui->actionEntryClone->setEnabled(false); m_ui->actionEntryClone->setEnabled(false);
m_ui->actionEntryEdit->setEnabled(false); m_ui->actionEntryEdit->setEnabled(false);
m_ui->actionGroupEdit->setEnabled(false);
m_ui->actionEntryDelete->setEnabled(false); m_ui->actionEntryDelete->setEnabled(false);
m_ui->actionEntryCopyUsername->setEnabled(false);
m_ui->actionEntryCopyPassword->setEnabled(false);
m_ui->actionGroupNew->setEnabled(false);
m_ui->actionGroupEdit->setEnabled(false);
m_ui->actionGroupDelete->setEnabled(false); m_ui->actionGroupDelete->setEnabled(false);
m_ui->actionSearch->setEnabled(false); m_ui->actionSearch->setEnabled(false);
m_ui->actionSearch->setChecked(false); m_ui->actionSearch->setChecked(false);
@ -154,11 +164,13 @@ void MainWindow::setMenuActionState(DatabaseWidget::Mode mode)
} }
else { else {
m_ui->actionEntryNew->setEnabled(false); m_ui->actionEntryNew->setEnabled(false);
m_ui->actionGroupNew->setEnabled(false);
m_ui->actionEntryClone->setEnabled(false); m_ui->actionEntryClone->setEnabled(false);
m_ui->actionEntryEdit->setEnabled(false); m_ui->actionEntryEdit->setEnabled(false);
m_ui->actionGroupEdit->setEnabled(false);
m_ui->actionEntryDelete->setEnabled(false); m_ui->actionEntryDelete->setEnabled(false);
m_ui->actionEntryCopyUsername->setEnabled(false);
m_ui->actionEntryCopyPassword->setEnabled(false);
m_ui->actionGroupNew->setEnabled(false);
m_ui->actionGroupEdit->setEnabled(false);
m_ui->actionGroupDelete->setEnabled(false); m_ui->actionGroupDelete->setEnabled(false);
m_ui->actionSearch->setEnabled(false); m_ui->actionSearch->setEnabled(false);
m_ui->actionSearch->setChecked(false); m_ui->actionSearch->setChecked(false);

View File

@ -70,6 +70,8 @@
<addaction name="actionEntryClone"/> <addaction name="actionEntryClone"/>
<addaction name="actionEntryEdit"/> <addaction name="actionEntryEdit"/>
<addaction name="actionEntryDelete"/> <addaction name="actionEntryDelete"/>
<addaction name="actionEntryCopyUsername"/>
<addaction name="actionEntryCopyPassword"/>
</widget> </widget>
<widget class="QMenu" name="menuGroups"> <widget class="QMenu" name="menuGroups">
<property name="title"> <property name="title">
@ -234,6 +236,22 @@
<string>Find</string> <string>Find</string>
</property> </property>
</action> </action>
<action name="actionEntryCopyUsername">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Copy username to clipboard</string>
</property>
</action>
<action name="actionEntryCopyPassword">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Copy password to clipboard</string>
</property>
</action>
</widget> </widget>
<customwidgets> <customwidgets>
<customwidget> <customwidget>

View File

@ -96,6 +96,10 @@ set(TEST_LIBRARIES
${ZLIB_LIBRARIES} ${ZLIB_LIBRARIES}
) )
if(UNIX AND NOT APPLE)
set(TEST_LIBRARIES ${TEST_LIBRARIES} ${QT_QTDBUS_LIBRARY})
endif()
set(modeltest_SOURCRS modeltest.cpp) set(modeltest_SOURCRS modeltest.cpp)
qt4_wrap_cpp(modeltest_SOURCRS modeltest.h) qt4_wrap_cpp(modeltest_SOURCRS modeltest.h)
add_library(modeltest STATIC ${modeltest_SOURCRS}) add_library(modeltest STATIC ${modeltest_SOURCRS})