2015-09-06 20:33:09 +02:00
# include "./mainwindow.h"
2015-11-04 20:30:32 +01:00
# include "./fielddelegate.h"
2015-09-06 20:33:09 +02:00
# include "../model/fieldmodel.h"
# include "../model/entrymodel.h"
# include "../model/entryfiltermodel.h"
2015-12-05 22:52:00 +01:00
# include "ui_mainwindow.h"
2015-04-22 19:30:09 +02:00
2016-04-25 22:06:24 +02:00
# include "resources/config.h"
2016-02-27 23:23:02 +01:00
2015-04-22 19:30:09 +02:00
# include <passwordfile/io/cryptoexception.h>
# include <passwordfile/io/entry.h>
# include <qtutilities/enterpassworddialog/enterpassworddialog.h>
2015-07-07 00:53:24 +02:00
# include <qtutilities/misc/dialogutils.h>
2016-02-06 17:05:27 +01:00
# include <qtutilities/misc/desktoputils.h>
2016-04-19 01:38:43 +02:00
# include <qtutilities/misc/recentmenumanager.h>
2016-07-04 23:29:49 +02:00
# include <qtutilities/aboutdialog/aboutdialog.h>
2016-08-16 00:37:17 +02:00
# include <qtutilities/settingsdialog/settingsdialog.h>
# include <qtutilities/settingsdialog/optioncategorymodel.h>
# include <qtutilities/settingsdialog/qtsettings.h>
2015-04-22 19:30:09 +02:00
# include <c++utilities/io/path.h>
2016-06-14 22:57:39 +02:00
# include <c++utilities/io/catchiofailure.h>
2016-03-03 16:50:37 +01:00
# include <c++utilities/conversion/stringconversion.h>
2015-04-22 19:30:09 +02:00
# include <QFileDialog>
# include <QMessageBox>
# include <QInputDialog>
# include <QActionGroup>
# include <QClipboard>
# include <QSettings>
# include <QCloseEvent>
# include <QTimerEvent>
# include <QUndoStack>
# include <QUndoView>
# include <QMimeData>
2016-03-03 16:50:37 +01:00
# include <QDesktopServices>
2015-04-22 19:30:09 +02:00
# include <stdexcept>
# include <cassert>
using namespace std ;
using namespace IoUtilities ;
using namespace Io ;
2015-09-26 20:34:09 +02:00
using namespace Dialogs ;
2016-04-19 01:38:43 +02:00
using namespace MiscUtils ;
2015-04-22 19:30:09 +02:00
namespace QtGui {
/*!
* \ namespace QtGui
* \ brief Contains all GUI related classes and helper functions .
*/
/*!
* \ namespace QtGui : : Ui
* \ brief Contains all classes generated by the Qt User Interface Compiler ( uic ) .
*/
/*!
* \ class MainWindow
* \ brief The MainWindow class provides the main window of the widgets - based GUI of the application .
*/
2015-06-21 21:37:45 +02:00
/*!
* \ brief Copies the selected cells to the clipboard .
*/
void MainWindow : : copyFields ( )
{
copyFieldsForXMilliSeconds ( - 1 ) ;
}
/*!
* \ brief Inserts fields from the clipboard .
*/
void MainWindow : : insertFieldsFromClipboard ( )
{
insertFields ( QApplication : : clipboard ( ) - > text ( ) ) ;
}
/*!
* \ brief Clears the clipboard .
*/
void MainWindow : : clearClipboard ( )
{
QApplication : : clipboard ( ) - > clear ( ) ;
}
/*!
* \ brief Flags the current file as being changed since the last save .
*/
void MainWindow : : setSomethingChanged ( )
{
setSomethingChanged ( true ) ;
}
/*!
* \ brief Sets whether the current file has been changed since the last save .
*/
void MainWindow : : setSomethingChanged ( bool somethingChanged )
{
if ( m_somethingChanged ! = somethingChanged ) {
m_somethingChanged = somethingChanged ;
updateWindowTitle ( ) ;
}
}
2015-04-22 19:30:09 +02:00
/*!
* \ brief Constructs a new main window .
*/
2016-08-16 00:37:17 +02:00
MainWindow : : MainWindow ( QSettings & settings , Dialogs : : QtSettings * qtSettings , QWidget * parent ) :
2015-04-22 19:30:09 +02:00
QMainWindow ( parent ) ,
m_ui ( new Ui : : MainWindow ) ,
2016-07-04 23:29:49 +02:00
m_clearClipboardTimer ( 0 ) ,
2016-08-16 00:37:17 +02:00
m_aboutDlg ( nullptr ) ,
m_settings ( settings ) ,
m_qtSettings ( qtSettings ) ,
m_settingsDlg ( nullptr )
2015-04-22 19:30:09 +02:00
{
// setup ui
m_ui - > setupUi ( this ) ;
# ifdef Q_OS_WIN32
2015-09-26 20:34:09 +02:00
setStyleSheet ( QStringLiteral ( " %1 #splitter QWidget { background-color: palette(base); color: palette(text); } #splitter QWidget *, #splitter QWidget * { background-color: none; } #leftWidget { border-right: 1px solid %2; } " ) . arg ( dialogStyle ( ) , windowFrameColor ( ) . name ( ) ) ) ;
2015-04-22 19:30:09 +02:00
# endif
// set default values
2015-06-21 21:37:45 +02:00
setSomethingChanged ( false ) ;
2015-04-22 19:30:09 +02:00
m_dontUpdateSelection = false ;
updateUiStatus ( ) ;
// load settings
settings . beginGroup ( QStringLiteral ( " mainwindow " ) ) ;
2016-04-19 01:38:43 +02:00
// init recent menu manager
m_recentMgr = new RecentMenuManager ( m_ui - > menuRecent , this ) ;
m_recentMgr - > restore ( settings . value ( QStringLiteral ( " recententries " ) , QStringList ( ) ) . toStringList ( ) ) ;
connect ( m_recentMgr , & RecentMenuManager : : fileSelected , this , & MainWindow : : openFile ) ;
2015-04-22 19:30:09 +02:00
// set position and size
2016-07-16 23:12:53 +02:00
restoreGeometry ( settings . value ( QStringLiteral ( " geometry " ) ) . toByteArray ( ) ) ;
restoreState ( settings . value ( QStringLiteral ( " state " ) ) . toByteArray ( ) ) ;
2015-04-22 19:30:09 +02:00
// setup undo stack and related actions
m_undoStack = new QUndoStack ( this ) ;
m_undoView = nullptr ;
m_ui - > actionUndo - > setShortcuts ( QKeySequence : : Undo ) ;
m_ui - > actionRedo - > setShortcuts ( QKeySequence : : Redo ) ;
// setup models, tree and table view
m_ui - > treeView - > setModel ( m_entryFilterModel = new EntryFilterModel ( this ) ) ;
m_ui - > tableView - > setModel ( m_fieldModel = new FieldModel ( m_undoStack , this ) ) ;
2015-11-04 20:30:32 +01:00
m_ui - > tableView - > setItemDelegate ( new FieldDelegate ( this ) ) ;
2015-04-22 19:30:09 +02:00
m_entryFilterModel - > setFilterCaseSensitivity ( Qt : : CaseInsensitive ) ;
m_entryFilterModel - > setSourceModel ( m_entryModel = new EntryModel ( m_undoStack , this ) ) ;
# ifdef Q_OS_WIN32
m_ui - > treeView - > setFrameShape ( QFrame : : NoFrame ) ;
m_ui - > tableView - > setFrameShape ( QFrame : : NoFrame ) ;
# else
m_ui - > treeView - > setFrameShape ( QFrame : : StyledPanel ) ;
m_ui - > tableView - > setFrameShape ( QFrame : : StyledPanel ) ;
# endif
m_ui - > tableView - > horizontalHeader ( ) - > setSectionResizeMode ( QHeaderView : : Stretch ) ;
// splitter sizes
m_ui - > splitter - > setSizes ( QList < int > ( ) < < 100 < < 800 ) ;
2015-11-03 21:22:50 +01:00
// password visibility group
auto * passwordVisibilityGroup = new QActionGroup ( this ) ;
passwordVisibilityGroup - > addAction ( m_ui - > actionShowAlways ) ;
passwordVisibilityGroup - > addAction ( m_ui - > actionShowOnlyWhenEditing ) ;
passwordVisibilityGroup - > addAction ( m_ui - > actionHideAlways ) ;
QString pwVisibility ( settings . value ( QStringLiteral ( " pwvisibility " ) ) . toString ( ) ) ;
QAction * pwVisibilityAction ;
if ( pwVisibility = = QStringLiteral ( " always " ) ) {
pwVisibilityAction = m_ui - > actionShowAlways ;
} else if ( pwVisibility = = QStringLiteral ( " hidden " ) ) {
pwVisibilityAction = m_ui - > actionHideAlways ;
} else {
pwVisibilityAction = m_ui - > actionShowOnlyWhenEditing ;
}
pwVisibilityAction - > setChecked ( true ) ;
setPasswordVisibility ( pwVisibilityAction ) ;
2015-04-22 19:30:09 +02:00
// connect signals and slots
2016-08-16 00:37:17 +02:00
// -> file related actions
2015-04-22 19:30:09 +02:00
connect ( m_ui - > actionSave , & QAction : : triggered , this , & MainWindow : : saveFile ) ;
connect ( m_ui - > actionExport , & QAction : : triggered , this , & MainWindow : : exportFile ) ;
connect ( m_ui - > actionShowContainingDirectory , & QAction : : triggered , this , & MainWindow : : showContainingDirectory ) ;
connect ( m_ui - > actionClose , & QAction : : triggered , this , & MainWindow : : closeFile ) ;
connect ( m_ui - > actionCreate , & QAction : : triggered , this , static_cast < bool ( MainWindow : : * ) ( void ) > ( & MainWindow : : createFile ) ) ;
connect ( m_ui - > actionQuit , & QAction : : triggered , this , & MainWindow : : close ) ;
connect ( m_ui - > actionChangepassword , & QAction : : triggered , this , & MainWindow : : changePassword ) ;
2016-08-16 00:37:17 +02:00
// -> showing dialogs
2015-04-22 19:30:09 +02:00
connect ( m_ui - > actionPasswordGenerator , & QAction : : triggered , this , & MainWindow : : showPassowrdGeneratorDialog ) ;
connect ( m_ui - > actionAbout , & QAction : : triggered , this , & MainWindow : : showAboutDialog ) ;
connect ( m_ui - > actionOpen , & QAction : : triggered , this , & MainWindow : : showOpenFileDialog ) ;
connect ( m_ui - > actionSaveAs , & QAction : : triggered , this , & MainWindow : : showSaveFileDialog ) ;
2016-08-16 00:37:17 +02:00
connect ( m_ui - > actionQtSettings , & QAction : : triggered , this , & MainWindow : : showSettingsDialog ) ;
// -> add/remove account
2015-04-22 19:30:09 +02:00
connect ( m_ui - > actionAddAccount , & QAction : : triggered , this , & MainWindow : : addAccount ) ;
connect ( m_ui - > actionAddCategory , & QAction : : triggered , this , & MainWindow : : addCategory ) ;
connect ( m_ui - > actionRemoveRows , & QAction : : triggered , this , & MainWindow : : removeEntry ) ;
2016-08-16 00:37:17 +02:00
// -> insert/remove fields
2015-04-22 19:30:09 +02:00
connect ( m_ui - > actionInsertRow , & QAction : : triggered , this , & MainWindow : : insertRow ) ;
connect ( m_ui - > actionRemoveAccount , & QAction : : triggered , this , & MainWindow : : removeRows ) ;
2016-08-16 00:37:17 +02:00
// -> undo/redo
2015-04-22 19:30:09 +02:00
connect ( m_ui - > actionUndo , & QAction : : triggered , m_undoStack , & QUndoStack : : undo ) ;
connect ( m_ui - > actionRedo , & QAction : : triggered , m_undoStack , & QUndoStack : : redo ) ;
connect ( m_undoStack , & QUndoStack : : canUndoChanged , m_ui - > actionUndo , & QAction : : setEnabled ) ;
connect ( m_undoStack , & QUndoStack : : canRedoChanged , m_ui - > actionRedo , & QAction : : setEnabled ) ;
2016-08-16 00:37:17 +02:00
// -> view
2015-11-03 21:22:50 +01:00
connect ( passwordVisibilityGroup , & QActionGroup : : triggered , this , & MainWindow : : setPasswordVisibility ) ;
2015-04-22 19:30:09 +02:00
connect ( m_ui - > actionShowUndoStack , & QAction : : triggered , this , & MainWindow : : showUndoView ) ;
2016-08-16 00:37:17 +02:00
// -> models
2015-04-22 19:30:09 +02:00
connect ( m_ui - > treeView - > selectionModel ( ) , & QItemSelectionModel : : currentRowChanged , this , & MainWindow : : accountSelected ) ;
2015-06-21 21:37:45 +02:00
connect ( m_entryModel , & QAbstractItemModel : : dataChanged , this , static_cast < void ( MainWindow : : * ) ( void ) > ( & MainWindow : : setSomethingChanged ) ) ;
connect ( m_fieldModel , & QAbstractItemModel : : dataChanged , this , static_cast < void ( MainWindow : : * ) ( void ) > ( & MainWindow : : setSomethingChanged ) ) ;
2016-08-16 00:37:17 +02:00
// -> context menus
2015-04-22 19:30:09 +02:00
connect ( m_ui - > treeView , & QTableView : : customContextMenuRequested , this , & MainWindow : : showTreeViewContextMenu ) ;
connect ( m_ui - > tableView , & QTableView : : customContextMenuRequested , this , & MainWindow : : showTableViewContextMenu ) ;
2016-08-16 00:37:17 +02:00
// -> filter
2015-04-22 19:30:09 +02:00
//connect(m_ui->accountFilterLineEdit, &QLineEdit::textChanged, m_entryFilterModel, &QSortFilterProxyModel::setFilterFixedString);
connect ( m_ui - > accountFilterLineEdit , & QLineEdit : : textChanged , this , & MainWindow : : applyFilter ) ;
// setup other controls
m_ui - > actionAlwaysCreateBackup - > setChecked ( settings . value ( QStringLiteral ( " alwayscreatebackup " ) , false ) . toBool ( ) ) ;
m_ui - > accountFilterLineEdit - > setText ( settings . value ( QStringLiteral ( " accountfilter " ) , QString ( ) ) . toString ( ) ) ;
2015-06-21 21:37:45 +02:00
m_ui - > centralWidget - > installEventFilter ( this ) ;
2015-04-22 19:30:09 +02:00
settings . endGroup ( ) ;
}
/*!
* \ brief Destroys the main window .
*/
MainWindow : : ~ MainWindow ( )
{ }
bool MainWindow : : eventFilter ( QObject * obj , QEvent * event )
{
if ( obj = = m_undoView ) {
switch ( event - > type ( ) ) {
case QEvent : : Hide :
m_ui - > actionShowUndoStack - > setChecked ( false ) ;
break ;
default :
;
}
2015-06-21 21:37:45 +02:00
} else if ( obj = = m_ui - > centralWidget ) {
switch ( event - > type ( ) ) {
case QEvent : : DragEnter :
case QEvent : : Drop :
if ( QDropEvent * dropEvent = static_cast < QDropEvent * > ( event ) ) {
QString data ;
const QMimeData * mimeData = dropEvent - > mimeData ( ) ;
if ( mimeData - > hasUrls ( ) ) {
const QUrl url = mimeData - > urls ( ) . front ( ) ;
if ( url . scheme ( ) = = QLatin1String ( " file " ) ) {
data = url . path ( ) ;
}
} else if ( mimeData - > hasText ( ) ) {
data = mimeData - > text ( ) ;
}
if ( ! data . isEmpty ( ) ) {
event - > accept ( ) ;
if ( event - > type ( ) = = QEvent : : Drop ) {
openFile ( data ) ;
}
}
return true ;
}
default :
;
}
2015-04-22 19:30:09 +02:00
}
return QMainWindow : : eventFilter ( obj , event ) ;
}
void MainWindow : : closeEvent ( QCloseEvent * event )
{
// ask if file is opened
if ( m_file . hasRootEntry ( ) ) {
if ( ! closeFile ( ) ) {
event - > ignore ( ) ;
return ;
}
}
// close undow view
if ( m_undoView ) {
m_undoView - > close ( ) ;
}
// save settings
2016-08-16 00:37:17 +02:00
m_settings . beginGroup ( QStringLiteral ( " mainwindow " ) ) ;
m_settings . setValue ( QStringLiteral ( " geometry " ) , saveGeometry ( ) ) ;
m_settings . setValue ( QStringLiteral ( " state " ) , saveState ( ) ) ;
m_settings . setValue ( QStringLiteral ( " recententries " ) , m_recentMgr - > save ( ) ) ;
m_settings . setValue ( QStringLiteral ( " accountfilter " ) , m_ui - > accountFilterLineEdit - > text ( ) ) ;
m_settings . setValue ( QStringLiteral ( " alwayscreatebackup " ) , m_ui - > actionAlwaysCreateBackup - > isChecked ( ) ) ;
2015-11-03 21:22:50 +01:00
QString pwVisibility ;
if ( m_ui - > actionShowAlways - > isChecked ( ) ) {
pwVisibility = QStringLiteral ( " always " ) ;
} else if ( m_ui - > actionHideAlways - > isChecked ( ) ) {
pwVisibility = QStringLiteral ( " hidden " ) ;
} else {
pwVisibility = QStringLiteral ( " editing " ) ;
}
2016-08-16 00:37:17 +02:00
m_settings . setValue ( QStringLiteral ( " pwvisibility " ) , pwVisibility ) ;
m_settings . endGroup ( ) ;
2015-04-22 19:30:09 +02:00
}
void MainWindow : : timerEvent ( QTimerEvent * event )
{
if ( event - > timerId ( ) = = m_clearClipboardTimer ) {
clearClipboard ( ) ;
m_clearClipboardTimer = 0 ;
}
}
2016-08-16 00:37:17 +02:00
/*!
* \ brief Shows the settings dialog ( which currently only consists of the Qt settings category ) .
*/
void MainWindow : : showSettingsDialog ( )
{
if ( ! m_settingsDlg ) {
m_settingsDlg = new SettingsDialog ( this ) ;
if ( m_qtSettings ) {
m_settingsDlg - > setWindowTitle ( tr ( " Qt settings " ) ) ;
m_settingsDlg - > setSingleCategory ( m_qtSettings - > category ( ) ) ;
}
//connect(m_settingsDlg, &SettingsDialog::applied, this, &MainWindow::settingsAccepted);
}
if ( m_settingsDlg - > isHidden ( ) ) {
m_settingsDlg - > showNormal ( ) ;
} else {
m_settingsDlg - > activateWindow ( ) ;
}
}
2015-04-22 19:30:09 +02:00
/*!
* \ brief Shows the about dialog .
*/
void MainWindow : : showAboutDialog ( )
{
2016-07-04 23:29:49 +02:00
if ( ! m_aboutDlg ) {
m_aboutDlg = new AboutDialog ( this , tr ( " A simple password store using AES-256-CBC encryption via OpenSSL. " ) , QImage ( " :/icons/hicolor/128x128/apps/passwordmanager.png " ) ) ;
}
m_aboutDlg - > show ( ) ;
2015-04-22 19:30:09 +02:00
}
/*!
* \ brief Shows the password generator dialog .
*/
void MainWindow : : showPassowrdGeneratorDialog ( )
{
PasswordGeneratorDialog * pwgDialog = new PasswordGeneratorDialog ( this ) ;
pwgDialog - > show ( ) ;
}
/*!
* \ brief Shows the open file dialog and opens the selected file .
*/
void MainWindow : : showOpenFileDialog ( )
{
if ( m_file . hasRootEntry ( ) & & ! closeFile ( ) ) {
return ;
}
2016-04-16 02:20:48 +02:00
QString fileName = QFileDialog : : getOpenFileName ( this , tr ( " Select a password list " ) , QString ( ) , tr ( " Password Manager files (*.pwmgr);;All files (*) " ) ) ;
2015-04-22 19:30:09 +02:00
if ( ! fileName . isEmpty ( ) ) {
openFile ( fileName ) ;
}
}
/*!
* \ brief Shows the save file dialog and saves the file at the selected location .
*/
void MainWindow : : showSaveFileDialog ( )
{
if ( showNoFileOpened ( ) ) {
return ;
}
if ( askForCreatingFile ( ) ) {
saveFile ( ) ;
}
}
/*!
* \ brief Shows the undo view .
*/
void MainWindow : : showUndoView ( )
{
if ( m_ui - > actionShowUndoStack - > isChecked ( ) ) {
if ( ! m_undoView ) {
m_undoView = new QUndoView ( m_undoStack ) ;
m_undoView - > setWindowTitle ( tr ( " Undo stack " ) ) ;
m_undoView - > setWindowFlags ( Qt : : Tool ) ;
m_undoView - > setAttribute ( Qt : : WA_QuitOnClose ) ;
m_undoView - > setWindowIcon ( QIcon : : fromTheme ( QStringLiteral ( " edit-undo " ) ) ) ;
m_undoView - > installEventFilter ( this ) ;
}
m_undoView - > show ( ) ;
} else if ( m_undoView ) {
m_undoView - > hide ( ) ;
}
}
/*!
* \ brief Opens a file with the specified \ a path and updates all widgets to show its contents .
* \ returns Returns true on success ; otherwise false
*/
bool MainWindow : : openFile ( const QString & path )
{
using namespace Dialogs ;
// close previous file
if ( m_file . hasRootEntry ( ) & & ! closeFile ( ) ) {
return false ;
}
// set path and open file
m_file . setPath ( path . toStdString ( ) ) ;
try {
m_file . open ( ) ;
2016-06-14 22:57:39 +02:00
} catch ( . . . ) {
const QString errmsg = tr ( " An IO error occured when opening the specified file \" %1 \" . \n \n (%2) " ) . arg ( path , QString : : fromLocal8Bit ( catchIoFailure ( ) ) ) ;
2015-04-22 19:30:09 +02:00
m_ui - > statusBar - > showMessage ( errmsg , 5000 ) ;
QMessageBox : : critical ( this , QApplication : : applicationName ( ) , errmsg ) ;
return false ;
}
// warn before loading a very big file
if ( m_file . size ( ) > 10485760 ) {
if ( QMessageBox : : warning ( this , QApplication : : applicationName ( ) , tr ( " The file you want to load seems to be very big. Do you really want to open it? " ) , QMessageBox : : Yes , QMessageBox : : No ) = = QMessageBox : : No ) {
m_file . clear ( ) ;
return false ;
}
}
// ask for a password if required
if ( m_file . isEncryptionUsed ( ) ) {
EnterPasswordDialog pwDlg ( this ) ;
2016-02-27 23:23:02 +01:00
pwDlg . setWindowTitle ( tr ( " Opening file " ) + QStringLiteral ( " - " APP_NAME ) ) ;
2015-12-19 01:34:12 +01:00
pwDlg . setInstruction ( tr ( " Enter the password to open the file \" %1 \" " ) . arg ( path ) ) ;
2015-04-22 19:30:09 +02:00
pwDlg . setPasswordRequired ( true ) ;
switch ( pwDlg . exec ( ) ) {
case QDialog : : Accepted :
if ( pwDlg . password ( ) . isEmpty ( ) ) {
m_ui - > statusBar - > showMessage ( tr ( " A password is needed to open the file. " ) , 5000 ) ;
QMessageBox : : warning ( this , QApplication : : applicationName ( ) , tr ( " A password is needed to open the file. " ) ) ;
m_file . clear ( ) ;
return false ;
} else {
break ;
}
case QDialog : : Rejected :
m_file . clear ( ) ;
return false ;
default :
;
}
m_file . setPassword ( pwDlg . password ( ) . toStdString ( ) ) ;
}
// load the contents of the file
QString msg ;
try {
m_file . load ( ) ;
2016-06-14 22:57:39 +02:00
} catch ( const CryptoException & e ) {
msg = tr ( " The file couldn't be decrypted. \n OpenSSL error queue: %1 " ) . arg ( QString : : fromLocal8Bit ( e . what ( ) ) ) ;
} catch ( . . . ) {
try {
msg = QString : : fromLocal8Bit ( catchIoFailure ( ) ) ;
} catch ( const runtime_error & e ) {
msg = tr ( " Unable to parse the file. %1 " ) . arg ( QString : : fromLocal8Bit ( e . what ( ) ) ) ;
}
2015-04-22 19:30:09 +02:00
}
// show a message in the error case
if ( ! msg . isEmpty ( ) ) {
m_file . clear ( ) ;
m_ui - > statusBar - > showMessage ( msg , 5000 ) ;
if ( QMessageBox : : critical ( this , QApplication : : applicationName ( ) , msg ,
QMessageBox : : Cancel , QMessageBox : : Retry ) = = QMessageBox : : Retry ) {
return openFile ( path ) ; // retry
} else {
return false ;
}
} else {
// show contents
return showFile ( ) ;
}
}
/*!
* \ brief Creates a new file .
* \ returns Returns true on success ; otherwise false
*/
bool MainWindow : : createFile ( )
{
// close previous file
if ( m_file . hasRootEntry ( ) & & ! closeFile ( ) ) {
return false ;
}
m_file . generateRootEntry ( ) ;
return showFile ( ) ;
}
/*!
* \ brief Creates a new file with the specified \ a path .
* \ returns Returns true on success ; otherwise false
*/
void MainWindow : : createFile ( const QString & path )
{
createFile ( path , QString ( ) ) ;
}
/*!
* \ brief Creates a new file with the specified \ a path and \ a password .
* \ returns Returns true on success ; otherwise false
*/
void MainWindow : : createFile ( const QString & path , const QString & password )
{
// close previous file
if ( m_file . hasRootEntry ( ) & & ! closeFile ( ) ) {
return ;
}
// set path and password
m_file . setPath ( path . toStdString ( ) ) ;
m_file . setPassword ( password . toStdString ( ) ) ;
// create the file and show it
try {
m_file . create ( ) ;
2016-06-14 22:57:39 +02:00
} catch ( . . . ) {
catchIoFailure ( ) ;
2015-04-22 19:30:09 +02:00
QMessageBox : : critical ( this , QApplication : : applicationName ( ) , tr ( " The file <i>%1</i> couldn't be created. " ) . arg ( path ) ) ;
return ;
}
m_file . generateRootEntry ( ) ;
showFile ( ) ;
}
/*!
* \ brief Shows the previously opened file . Called within openFile ( ) and createFile ( ) .
* \ returns Returns true on success ; otherwise false
*/
bool MainWindow : : showFile ( )
{
m_fieldModel - > reset ( ) ;
m_entryModel - > setRootEntry ( m_file . rootEntry ( ) ) ;
applyDefaultExpanding ( QModelIndex ( ) ) ;
if ( m_file . path ( ) . empty ( ) ) {
m_ui - > statusBar - > showMessage ( tr ( " A new password list has been created. " ) , 5000 ) ;
} else {
2016-04-19 01:38:43 +02:00
m_recentMgr - > addEntry ( QString : : fromStdString ( m_file . path ( ) ) ) ;
2015-06-21 21:37:45 +02:00
m_ui - > statusBar - > showMessage ( tr ( " The password list has been load. " ) , 5000 ) ;
2015-04-22 19:30:09 +02:00
}
2015-06-21 21:37:45 +02:00
updateWindowTitle ( ) ;
2015-04-22 19:30:09 +02:00
updateUiStatus ( ) ;
applyFilter ( m_ui - > accountFilterLineEdit - > text ( ) ) ;
2015-06-21 21:37:45 +02:00
setSomethingChanged ( false ) ;
2015-04-22 19:30:09 +02:00
return true ;
}
/*!
* \ brief Updates the status of the UI elements .
*/
void MainWindow : : updateUiStatus ( )
{
bool fileOpened = m_file . hasRootEntry ( ) ;
m_ui - > actionCreate - > setEnabled ( true ) ;
m_ui - > actionOpen - > setEnabled ( true ) ;
m_ui - > actionSave - > setEnabled ( fileOpened ) ;
m_ui - > actionSaveAs - > setEnabled ( fileOpened ) ;
m_ui - > actionExport - > setEnabled ( fileOpened ) ;
m_ui - > actionShowContainingDirectory - > setEnabled ( fileOpened ) ;
m_ui - > actionClose - > setEnabled ( fileOpened ) ;
m_ui - > actionChangepassword - > setEnabled ( fileOpened ) ;
m_ui - > menuEdit - > setEnabled ( fileOpened ) ;
m_ui - > accountFilterLineEdit - > setEnabled ( true ) ;
}
2015-06-21 21:37:45 +02:00
/*!
* \ brief Updates the window title .
*/
void MainWindow : : updateWindowTitle ( )
{
2015-07-07 00:53:24 +02:00
Dialogs : : DocumentStatus docStatus ;
if ( m_file . hasRootEntry ( ) ) {
2015-06-21 21:37:45 +02:00
if ( m_somethingChanged ) {
2015-07-07 00:53:24 +02:00
docStatus = Dialogs : : DocumentStatus : : Unsaved ;
2015-06-21 21:37:45 +02:00
} else {
2015-07-07 00:53:24 +02:00
docStatus = Dialogs : : DocumentStatus : : Saved ;
2015-06-21 21:37:45 +02:00
}
2015-07-07 00:53:24 +02:00
} else {
docStatus = Dialogs : : DocumentStatus : : NoDocument ;
2015-06-21 21:37:45 +02:00
}
2015-07-07 00:53:24 +02:00
setWindowTitle ( Dialogs : : generateWindowTitle ( docStatus , QString : : fromStdString ( m_file . path ( ) ) ) ) ;
2015-06-21 21:37:45 +02:00
}
2015-04-22 19:30:09 +02:00
void MainWindow : : applyDefaultExpanding ( const QModelIndex & parent )
{
for ( int row = 0 , rows = m_entryFilterModel - > rowCount ( parent ) ; row < rows ; + + row ) {
QModelIndex index = m_entryFilterModel - > index ( row , 0 , parent ) ;
if ( ! index . isValid ( ) ) {
return ;
}
applyDefaultExpanding ( index ) ;
m_ui - > treeView - > setExpanded ( index , m_entryFilterModel - > data ( index , DefaultExpandedRole ) . toBool ( ) ) ;
}
}
/*!
* \ brief Returns a string with the values of all selected fields .
* \ remarks Columns are sparated with \ t , rows with \ n .
*/
QString MainWindow : : selectedFieldsString ( ) const
{
QModelIndexList selectedIndexes = m_ui - > tableView - > selectionModel ( ) - > selectedIndexes ( ) ;
QString text ;
if ( ! selectedIndexes . isEmpty ( ) ) {
if ( selectedIndexes . size ( ) > 1 ) {
int maxRow = m_fieldModel - > rowCount ( ) - 1 ;
int firstRow = maxRow , lastRow = 0 ;
int maxCol = m_fieldModel - > columnCount ( ) - 1 ;
int firstCol = maxCol , lastCol = 0 ;
for ( const QModelIndex & index : selectedIndexes ) {
if ( index . row ( ) < firstRow ) {
firstRow = index . row ( ) ;
}
if ( index . row ( ) > lastRow ) {
lastRow = index . row ( ) ;
}
if ( index . column ( ) < firstCol ) {
firstCol = index . column ( ) ;
}
if ( index . column ( ) > lastCol ) {
lastCol = index . column ( ) ;
}
}
for ( int row = firstRow ; row < = lastRow ; + + row ) {
for ( int col = firstCol ; col < = lastCol ; + + col ) {
QModelIndex index = m_fieldModel - > index ( row , col ) ;
if ( selectedIndexes . contains ( index ) ) {
text . append ( index . data ( Qt : : EditRole ) . toString ( ) ) ;
}
text . append ( ' \t ' ) ;
}
text . append ( ' \n ' ) ;
}
} else {
text = selectedIndexes . front ( ) . data ( Qt : : EditRole ) . toString ( ) ;
}
}
return text ;
}
/*!
* \ brief Inserts fields from the specified \ a fieldsString .
*/
void MainWindow : : insertFields ( const QString & fieldsString )
{
QModelIndexList selectedIndexes = m_ui - > tableView - > selectionModel ( ) - > selectedIndexes ( ) ;
if ( selectedIndexes . size ( ) = = 1 ) {
int rows = m_fieldModel - > rowCount ( ) , cols = m_fieldModel - > columnCount ( ) ;
int row = selectedIndexes . front ( ) . row ( ) ;
int initCol = selectedIndexes . front ( ) . column ( ) ;
assert ( row < rows ) ;
QStringList rowValues = fieldsString . split ( ' \n ' ) ;
if ( rowValues . back ( ) . isEmpty ( ) ) {
rowValues . pop_back ( ) ;
}
m_fieldModel - > insertRows ( row , rowValues . size ( ) , QModelIndex ( ) ) ;
for ( const QString & rowValue : rowValues ) {
int col = initCol ;
for ( const QString & cellValue : rowValue . split ( ' \t ' ) ) {
if ( col < cols ) {
m_fieldModel - > setData ( m_fieldModel - > index ( row , col ) , cellValue , Qt : : EditRole ) ;
+ + col ;
} else {
break ;
}
}
+ + row ;
}
} else {
QMessageBox : : warning ( this , QApplication : : applicationName ( ) , tr ( " Exactly one fields needs to be selected (top-left corner for insertion). " ) ) ;
}
}
/*!
* \ brief Asks the user to create a new file .
*/
bool MainWindow : : askForCreatingFile ( )
{
if ( showNoFileOpened ( ) ) {
return false ;
}
QString fileName =
QFileDialog : : getSaveFileName (
this ,
tr ( " Select where you want to save the password list " ) ,
QString ( ) ,
2016-04-16 02:20:48 +02:00
tr ( " Password Manager files (*.pwmgr);;All files (*) " ) ) ;
2015-04-22 19:30:09 +02:00
if ( fileName . isEmpty ( ) ) {
m_ui - > statusBar - > showMessage ( tr ( " The file was not be saved. " ) , 7000 ) ;
return false ;
} else {
m_file . setPath ( fileName . toStdString ( ) ) ;
try {
m_file . create ( ) ;
2016-04-16 02:20:48 +02:00
updateWindowTitle ( ) ;
2016-06-14 22:57:39 +02:00
} catch ( . . . ) {
QMessageBox : : critical ( this , QApplication : : applicationName ( ) , QString : : fromLocal8Bit ( catchIoFailure ( ) ) ) ;
2015-04-22 19:30:09 +02:00
return false ;
}
}
return true ;
}
/*!
* \ brief Shows an warning if no file is opened .
* \ retruns Returns whether the warning has been shown .
*/
bool MainWindow : : showNoFileOpened ( )
{
if ( ! m_file . hasRootEntry ( ) ) {
QMessageBox : : warning ( this , QApplication : : applicationName ( ) , tr ( " There is no password list opened. " ) ) ;
return true ;
}
return false ;
}
/*!
* \ brief Shows an warning if no account is selected .
* \ retruns Returns whether the warning has been shown .
*/
bool MainWindow : : showNoAccount ( )
{
if ( ! m_fieldModel - > fields ( ) ) {
QMessageBox : : warning ( this , QApplication : : applicationName ( ) , tr ( " There's no account selected. " ) ) ;
return true ;
}
return false ;
}
/*!
* \ brief Closes the currently opened file . Asks the user to save changes if the file has been modified .
* \ returns Returns whether the file has been closed .
*/
bool MainWindow : : closeFile ( )
{
if ( showNoFileOpened ( ) ) {
return false ;
}
if ( m_somethingChanged ) {
QMessageBox msg ( this ) ;
msg . setText ( tr ( " The password file has been modified. " ) ) ;
msg . setInformativeText ( tr ( " Do you want to save the changes before closing? " ) ) ;
msg . setStandardButtons ( QMessageBox : : Save | QMessageBox : : Discard | QMessageBox : : Cancel ) ;
msg . setDefaultButton ( QMessageBox : : Save ) ;
msg . setIcon ( QMessageBox : : Warning ) ;
switch ( msg . exec ( ) ) {
case QMessageBox : : Save :
if ( saveFile ( ) ) {
break ;
} else {
return false ;
}
case QMessageBox : : Cancel :
return false ;
default :
;
}
}
m_fieldModel - > reset ( ) ;
m_entryModel - > reset ( ) ;
m_file . clear ( ) ;
m_ui - > statusBar - > showMessage ( tr ( " The password list has been closed. " ) ) ;
2015-06-21 21:37:45 +02:00
updateWindowTitle ( ) ;
2015-04-22 19:30:09 +02:00
updateUiStatus ( ) ;
2015-06-21 21:37:45 +02:00
setSomethingChanged ( false ) ;
2015-04-22 19:30:09 +02:00
return true ;
}
/*!
* \ brief Saves the currently opened file .
* \ returns Returns whether the file could be saved .
*/
bool MainWindow : : saveFile ( )
{
using namespace Dialogs ;
if ( showNoFileOpened ( ) ) {
return false ;
}
// create backup
if ( ! m_file . path ( ) . empty ( ) & & QFile : : exists ( QString : : fromStdString ( m_file . path ( ) ) ) ) {
if ( m_ui - > actionAlwaysCreateBackup - > isChecked ( ) ) {
try {
m_file . doBackup ( ) ;
2016-06-14 22:57:39 +02:00
} catch ( . . . ) {
QString message ( tr ( " The backup file couldn't be created because in IO error occured: %1 " ) . arg ( QString : : fromLocal8Bit ( catchIoFailure ( ) ) ) ) ;
2015-04-22 19:30:09 +02:00
QMessageBox : : critical ( this , QApplication : : applicationName ( ) , message ) ;
m_ui - > statusBar - > showMessage ( message , 7000 ) ;
return false ;
}
}
} else {
if ( ! askForCreatingFile ( ) ) {
return false ;
}
}
// ask for a password if none is set
if ( m_file . password ( ) [ 0 ] = = 0 ) {
EnterPasswordDialog pwDlg ( this ) ;
2016-02-27 23:23:02 +01:00
pwDlg . setWindowTitle ( tr ( " Saving file " ) + QStringLiteral ( " - " APP_NAME ) ) ;
2015-04-22 19:30:09 +02:00
pwDlg . setInstruction ( tr ( " Enter a password to save the file " ) ) ;
pwDlg . setVerificationRequired ( true ) ;
switch ( pwDlg . exec ( ) ) {
case QDialog : : Accepted :
m_file . setPassword ( pwDlg . password ( ) . toStdString ( ) ) ;
break ;
default :
m_ui - > statusBar - > showMessage ( tr ( " The file hasn't been saved. " ) , 7000 ) ;
return false ;
}
}
// save the file
QString msg ;
try {
m_file . save ( m_file . password ( ) [ 0 ] ! = 0 ) ;
2016-04-16 02:20:48 +02:00
} catch ( const CryptoException & ex ) {
2015-04-22 19:30:09 +02:00
msg = tr ( " The password list couldn't be saved due to encryption failure. \n OpenSSL error queue: %1 " ) . arg ( QString : : fromLocal8Bit ( ex . what ( ) ) ) ;
2016-06-14 22:57:39 +02:00
} catch ( . . . ) {
msg = QString : : fromLocal8Bit ( catchIoFailure ( ) ) ;
2015-04-22 19:30:09 +02:00
}
// show status
if ( ! msg . isEmpty ( ) ) {
m_ui - > statusBar - > showMessage ( msg , 5000 ) ;
QMessageBox : : critical ( this , QApplication : : applicationName ( ) , msg ) ;
return false ;
} else {
2015-06-21 21:37:45 +02:00
setSomethingChanged ( false ) ;
2016-04-19 01:38:43 +02:00
m_recentMgr - > addEntry ( QString : : fromStdString ( m_file . path ( ) ) ) ;
2015-04-22 19:30:09 +02:00
m_ui - > statusBar - > showMessage ( tr ( " The password list has been saved. " ) , 5000 ) ;
return true ;
}
}
/*!
* \ brief Exports the files contents to a plain text file .
*/
void MainWindow : : exportFile ( )
{
if ( showNoFileOpened ( ) ) {
return ;
}
2016-04-16 02:20:48 +02:00
QString targetPath = QFileDialog : : getSaveFileName ( this , QApplication : : applicationName ( ) , QString ( ) , tr ( " Plain text document (*.txt);;All files (*.*) " ) ) ;
2015-04-22 19:30:09 +02:00
if ( ! targetPath . isNull ( ) ) {
QString errmsg ;
try {
m_file . exportToTextfile ( targetPath . toStdString ( ) ) ;
2016-06-14 22:57:39 +02:00
} catch ( . . . ) {
errmsg = tr ( " The password list couldn't be exported. %1 " ) . arg ( QString : : fromLocal8Bit ( catchIoFailure ( ) ) ) ;
2015-04-22 19:30:09 +02:00
}
if ( errmsg . isEmpty ( ) ) {
m_ui - > statusBar - > showMessage ( tr ( " The password list has been exported. " ) , 5000 ) ;
} else {
m_ui - > statusBar - > showMessage ( errmsg , 5000 ) ;
QMessageBox : : critical ( this , QApplication : : applicationName ( ) , errmsg ) ;
}
}
}
/*!
* \ brief Shows the containing directory for the currently opened file .
*/
void MainWindow : : showContainingDirectory ( )
{
if ( showNoFileOpened ( ) ) {
return ;
} else if ( m_file . path ( ) . empty ( ) ) {
QMessageBox : : warning ( this , QApplication : : applicationName ( ) , tr ( " The currently opened file hasn't been saved yet. " ) ) ;
} else {
QFileInfo file ( QString : : fromStdString ( m_file . path ( ) ) ) ;
if ( file . dir ( ) . exists ( ) ) {
2016-02-06 17:05:27 +01:00
DesktopUtils : : openLocalFileOrDir ( file . dir ( ) . absolutePath ( ) ) ;
2015-04-22 19:30:09 +02:00
}
}
}
/*!
* \ brief Adds a new account entry to the selected category .
*/
void MainWindow : : addAccount ( )
{
addEntry ( EntryType : : Account ) ;
}
/*!
* \ brief Adds a new category / node entry to the selected category .
*/
void MainWindow : : addCategory ( )
{
addEntry ( EntryType : : Node ) ;
}
/*!
* \ brief Adds a new entry to the selected category .
* \ param type Specifies the type of the entry to be created .
* \ param title Specifies the title of the user prompt which will be shown to ask for the entry label .
*/
void MainWindow : : addEntry ( EntryType type )
{
if ( showNoFileOpened ( ) ) {
return ;
}
QModelIndexList selectedIndexes = m_ui - > treeView - > selectionModel ( ) - > selectedRows ( 0 ) ;
if ( selectedIndexes . size ( ) = = 1 ) {
QModelIndex selected = m_entryFilterModel - > mapToSource ( selectedIndexes . at ( 0 ) ) ;
if ( m_entryModel - > isNode ( selected ) ) {
bool result ;
2016-02-06 17:05:27 +01:00
const QString text = QInputDialog : : getText ( this , type = = EntryType : : Account ? tr ( " Add account " ) : tr ( " Add category " ) , tr ( " Enter the entry name " ) , QLineEdit : : Normal , tr ( " new entry " ) , & result ) ;
2015-04-22 19:30:09 +02:00
if ( result ) {
if ( ! text . isEmpty ( ) ) {
int row = m_entryModel - > rowCount ( selected ) ;
m_entryModel - > setInsertType ( type ) ;
if ( m_entryModel - > insertRow ( row , selected ) ) {
m_entryModel - > setData ( m_entryModel - > index ( row , 0 , selected ) , text , Qt : : DisplayRole ) ;
2015-06-21 21:37:45 +02:00
setSomethingChanged ( true ) ;
2015-04-22 19:30:09 +02:00
} else {
QMessageBox : : warning ( this , QApplication : : applicationName ( ) , tr ( " Unable to create new entry. " ) ) ;
}
} else {
QMessageBox : : warning ( this , QApplication : : applicationName ( ) , tr ( " You didn't enter text. " ) ) ;
}
}
return ;
}
}
QMessageBox : : warning ( this , QApplication : : applicationName ( ) , tr ( " No node element selected. " ) ) ;
}
/*!
* \ brief Removes the selected entry .
*/
void MainWindow : : removeEntry ( )
{
if ( showNoFileOpened ( ) ) {
return ;
}
QModelIndexList selectedIndexes = m_ui - > treeView - > selectionModel ( ) - > selectedRows ( 0 ) ;
if ( selectedIndexes . size ( ) = = 1 ) {
2016-02-06 17:05:27 +01:00
const QModelIndex selected = m_entryFilterModel - > mapToSource ( selectedIndexes . at ( 0 ) ) ;
2015-04-22 19:30:09 +02:00
if ( ! m_entryModel - > removeRow ( selected . row ( ) , selected . parent ( ) ) ) {
QMessageBox : : warning ( this , QApplication : : applicationName ( ) , tr ( " Unable to remove the entry. " ) ) ;
}
} else {
QMessageBox : : warning ( this , QApplication : : applicationName ( ) , tr ( " No entry selected. " ) ) ;
}
}
/*!
* \ brief Applies the entered filter .
* \ remarks Called when the textChanged signal of m_ui - > accountFilterLineEdit is emittet .
*/
void MainWindow : : applyFilter ( const QString & filterText )
{
2016-04-08 00:04:23 +02:00
m_entryFilterModel - > setFilterRegExp ( filterText ) ;
2015-04-22 19:30:09 +02:00
if ( filterText . isEmpty ( ) ) {
applyDefaultExpanding ( QModelIndex ( ) ) ;
} else {
m_ui - > treeView - > expandAll ( ) ;
}
}
/*!
* \ brief Called when the user \ a selected an entry .
*/
void MainWindow : : accountSelected ( const QModelIndex & selected , const QModelIndex & )
{
if ( Entry * entry = m_entryModel - > entry ( m_entryFilterModel - > mapToSource ( selected ) ) ) {
if ( entry - > type ( ) = = EntryType : : Account ) {
m_fieldModel - > setAccountEntry ( static_cast < AccountEntry * > ( entry ) ) ;
return ;
}
}
m_fieldModel - > setAccountEntry ( nullptr ) ;
}
/*!
* \ brief Inserts an empty row before the selected one .
*/
void MainWindow : : insertRow ( )
{
if ( showNoFileOpened ( ) | | showNoAccount ( ) ) {
return ;
}
QModelIndexList selectedIndexes = m_ui - > tableView - > selectionModel ( ) - > selectedIndexes ( ) ;
if ( selectedIndexes . size ( ) ) {
int row = m_fieldModel - > rowCount ( ) ;
2016-02-06 17:05:27 +01:00
for ( const QModelIndex & index : selectedIndexes ) {
2015-04-22 19:30:09 +02:00
if ( index . row ( ) < row ) {
row = index . row ( ) ;
}
}
if ( row < m_fieldModel - > rowCount ( ) - 1 ) {
m_fieldModel - > insertRow ( row ) ;
}
} else {
QMessageBox : : warning ( this , windowTitle ( ) , tr ( " A field has to be selected since new fields are always inserted before the currently selected field. " ) ) ;
}
}
/*!
* \ brief Removes the selected rows .
*/
void MainWindow : : removeRows ( )
{
if ( showNoFileOpened ( ) | | showNoAccount ( ) ) {
return ;
}
2016-02-06 17:05:27 +01:00
const QModelIndexList selectedIndexes = m_ui - > tableView - > selectionModel ( ) - > selectedIndexes ( ) ;
2015-04-22 19:30:09 +02:00
QList < int > rows ;
2016-02-06 17:05:27 +01:00
for ( const QModelIndex & index : selectedIndexes ) {
2015-04-22 19:30:09 +02:00
rows < < index . row ( ) ;
}
if ( rows . size ( ) ) {
for ( int i = m_fieldModel - > rowCount ( ) - 1 ; i > = 0 ; - - i ) {
if ( rows . contains ( i ) ) {
m_fieldModel - > removeRow ( i ) ;
}
}
} else {
QMessageBox : : warning ( this , windowTitle ( ) , tr ( " No fields have been removed since there are currently no fields selected. " ) ) ;
}
}
/*!
* \ brief Marks the selected field as password field .
*/
void MainWindow : : markAsPasswordField ( )
{
setFieldType ( FieldType : : Password ) ;
}
/*!
* \ brief Marks the selected field as normal field .
*/
void MainWindow : : markAsNormalField ( )
{
setFieldType ( FieldType : : Normal ) ;
}
/*!
* \ brief Sets the type of the selected field to the specified \ a fieldType .
*/
void MainWindow : : setFieldType ( FieldType fieldType )
{
if ( showNoFileOpened ( ) | | showNoAccount ( ) ) {
return ;
}
QModelIndexList selectedIndexes = m_ui - > tableView - > selectionModel ( ) - > selectedIndexes ( ) ;
if ( ! selectedIndexes . isEmpty ( ) ) {
2016-02-06 17:05:27 +01:00
const QVariant typeVariant ( static_cast < int > ( fieldType ) ) ;
for ( const QModelIndex & index : selectedIndexes ) {
2015-04-22 19:30:09 +02:00
m_fieldModel - > setData ( index , typeVariant , FieldTypeRole ) ;
}
} else {
QMessageBox : : warning ( this , windowTitle ( ) , tr ( " No fields have been changed since there are currently no fields selected. " ) ) ;
}
}
2015-11-03 21:22:50 +01:00
/*!
* \ brief Sets the password visibility of m_fieldModel depending on which action has been chosen .
*
* This private slot is connected to the triggered signal of the passwordVisibility QActionGroup .
*/
void MainWindow : : setPasswordVisibility ( QAction * selectedAction )
{
if ( selectedAction = = m_ui - > actionShowAlways ) {
m_fieldModel - > setPasswordVisibility ( PasswordVisibility : : Always ) ;
} else if ( selectedAction = = m_ui - > actionShowOnlyWhenEditing ) {
m_fieldModel - > setPasswordVisibility ( PasswordVisibility : : OnlyWhenEditing ) ;
} else if ( selectedAction = = m_ui - > actionHideAlways ) {
m_fieldModel - > setPasswordVisibility ( PasswordVisibility : : Never ) ;
}
}
2015-04-22 19:30:09 +02:00
/*!
* \ brief Asks the user to change the password which will be used when calling saveFile ( ) next time .
*/
void MainWindow : : changePassword ( )
{
using namespace Dialogs ;
2015-06-21 21:37:45 +02:00
if ( showNoFileOpened ( ) ) {
return ;
}
2015-04-22 19:30:09 +02:00
EnterPasswordDialog pwDlg ( this ) ;
2016-02-27 23:23:02 +01:00
pwDlg . setWindowTitle ( tr ( " Changing password " ) + QStringLiteral ( " - " APP_NAME ) ) ;
2015-04-22 19:30:09 +02:00
pwDlg . setVerificationRequired ( true ) ;
switch ( pwDlg . exec ( ) ) {
case QDialog : : Accepted :
if ( pwDlg . password ( ) . isEmpty ( ) ) {
m_file . clearPassword ( ) ;
2015-06-21 21:37:45 +02:00
setSomethingChanged ( true ) ;
2015-04-22 19:30:09 +02:00
QMessageBox : : warning ( this , QApplication : : applicationName ( ) , tr ( " You didn't enter a password. <strong>No encryption</strong> will be used when saving the file next time. " ) ) ;
} else {
m_file . setPassword ( pwDlg . password ( ) . toStdString ( ) ) ;
2015-06-21 21:37:45 +02:00
setSomethingChanged ( true ) ;
2015-04-22 19:30:09 +02:00
QMessageBox : : warning ( this , QApplication : : applicationName ( ) , tr ( " The new password will be used next time you save the file. " ) ) ;
}
break ;
default :
QMessageBox : : warning ( this , QApplication : : applicationName ( ) , tr ( " You aborted. The old password will still be used when saving the file next time. " ) ) ;
}
}
/*!
* \ brief Shows the tree view context menu .
*/
void MainWindow : : showTreeViewContextMenu ( )
{
if ( ! m_file . hasRootEntry ( ) ) {
return ;
}
QModelIndexList selectedIndexes = m_ui - > treeView - > selectionModel ( ) - > selectedRows ( 0 ) ;
if ( selectedIndexes . size ( ) = = 1 ) {
QMenu contextMenu ( this ) ;
QModelIndex selected = m_entryFilterModel - > mapToSource ( selectedIndexes . at ( 0 ) ) ;
Entry * entry = m_entryModel - > entry ( selected ) ;
if ( entry - > type ( ) = = EntryType : : Node ) {
contextMenu . addAction ( QIcon : : fromTheme ( QStringLiteral ( " list-add " ) ) , tr ( " Add account " ) , this , SLOT ( addAccount ( ) ) ) ;
contextMenu . addAction ( QIcon : : fromTheme ( QStringLiteral ( " list-add " ) ) , tr ( " Add category " ) , this , SLOT ( addCategory ( ) ) ) ;
}
contextMenu . addAction ( QIcon : : fromTheme ( QStringLiteral ( " list-remove " ) ) , tr ( " Remove entry " ) , this , SLOT ( removeEntry ( ) ) ) ;
if ( entry - > type ( ) = = EntryType : : Node ) {
NodeEntry * nodeEntry = static_cast < NodeEntry * > ( entry ) ;
contextMenu . addSeparator ( ) ;
QAction * action = new QAction ( & contextMenu ) ;
action - > setCheckable ( true ) ;
action - > setText ( tr ( " Expanded by default " ) ) ;
action - > setChecked ( nodeEntry - > isExpandedByDefault ( ) ) ;
connect ( action , & QAction : : triggered , std : : bind ( & EntryModel : : setData , m_entryModel , std : : cref ( selected ) , QVariant ( ! nodeEntry - > isExpandedByDefault ( ) ) , DefaultExpandedRole ) ) ;
contextMenu . addAction ( action ) ;
}
contextMenu . exec ( QCursor : : pos ( ) ) ;
}
}
/*!
* \ brief Shows the table view context menu .
*/
void MainWindow : : showTableViewContextMenu ( )
{
2016-03-03 16:50:37 +01:00
// check whether there is a selection at all
2015-04-22 19:30:09 +02:00
QModelIndexList selectedIndexes = m_ui - > tableView - > selectionModel ( ) - > selectedIndexes ( ) ;
if ( ! m_file . hasRootEntry ( ) | | ! m_fieldModel - > fields ( ) | | selectedIndexes . isEmpty ( ) ) {
return ;
}
2016-03-03 16:50:37 +01:00
// check what kind of fields have been selected
2016-02-06 17:05:27 +01:00
auto firstType = FieldType : : Normal ;
2015-04-22 19:30:09 +02:00
bool allOfSameType = true ;
2016-03-03 16:50:37 +01:00
bool hasFirstFieldType = false ;
2015-04-22 19:30:09 +02:00
int row = selectedIndexes . front ( ) . row ( ) ;
int multipleRows = 1 ;
2016-03-03 16:50:37 +01:00
QUrl url ;
static const string protocols [ ] = {
" http: " , " https: " , " file: "
} ;
2016-02-06 17:05:27 +01:00
for ( const QModelIndex & index : selectedIndexes ) {
2015-04-22 19:30:09 +02:00
if ( const Field * field = m_fieldModel - > field ( index . row ( ) ) ) {
2016-03-03 16:50:37 +01:00
if ( url . isEmpty ( ) & & field - > type ( ) ! = FieldType : : Password ) {
for ( const string & protocol : protocols ) {
if ( ConversionUtilities : : startsWith ( field - > value ( ) , protocol ) ) {
url = QString : : fromUtf8 ( field - > value ( ) . data ( ) ) ;
}
}
}
if ( hasFirstFieldType ) {
2015-04-22 19:30:09 +02:00
if ( firstType ! = field - > type ( ) ) {
allOfSameType = false ;
break ;
}
} else {
firstType = field - > type ( ) ;
2016-03-03 16:50:37 +01:00
hasFirstFieldType = true ;
2015-04-22 19:30:09 +02:00
}
}
if ( multipleRows = = 1 & & index . row ( ) ! = row ) {
+ + multipleRows ;
}
}
2016-03-03 16:50:37 +01:00
// create context menu
QMenu contextMenu ( this ) ;
// -> insertion and removal
contextMenu . addAction ( QIcon : : fromTheme ( QStringLiteral ( " list-add " ) ) , tr ( " Insert field " ) , this , SLOT ( insertRow ( ) ) ) ;
2016-03-03 16:50:44 +01:00
contextMenu . addAction ( QIcon : : fromTheme ( QStringLiteral ( " list-remove " ) ) , tr ( " Remove field(s) " , 0 , multipleRows ) , this , SLOT ( removeRows ( ) ) ) ;
2016-03-03 16:50:37 +01:00
// -> show the "Mark as ..." action only when all selected indexes are of the same type
if ( hasFirstFieldType & & allOfSameType ) {
2015-04-22 19:30:09 +02:00
switch ( firstType ) {
case FieldType : : Normal :
2016-03-03 16:50:37 +01:00
contextMenu . addAction ( QIcon : : fromTheme ( QStringLiteral ( " flag-black " ) ) , tr ( " Mark as password field " ) , this , SLOT ( markAsPasswordField ( ) ) ) ;
2015-04-22 19:30:09 +02:00
break ;
case FieldType : : Password :
2016-03-03 16:50:37 +01:00
contextMenu . addAction ( QIcon : : fromTheme ( QStringLiteral ( " flag-blue " ) ) , tr ( " Mark as normal field " ) , this , SLOT ( markAsNormalField ( ) ) ) ;
2015-04-22 19:30:09 +02:00
break ;
}
}
2016-03-03 16:50:37 +01:00
// -> insert copy & paste
2015-04-22 19:30:09 +02:00
contextMenu . addSeparator ( ) ;
2016-03-03 16:50:37 +01:00
contextMenu . addAction ( QIcon : : fromTheme ( QStringLiteral ( " edit-copy " ) ) , tr ( " Copy " ) , this , SLOT ( copyFields ( ) ) ) ;
contextMenu . addAction ( QIcon : : fromTheme ( QStringLiteral ( " edit-copy " ) ) , tr ( " Copy for 5 seconds " ) , this , SLOT ( copyFieldsForXMilliSeconds ( ) ) ) ;
2015-04-22 19:30:09 +02:00
if ( QApplication : : clipboard ( ) - > mimeData ( ) - > hasText ( ) ) {
2016-03-03 16:50:37 +01:00
contextMenu . addAction ( QIcon : : fromTheme ( QStringLiteral ( " edit-paste " ) ) , tr ( " Paste " ) , this , SLOT ( insertFieldsFromClipboard ( ) ) ) ;
2015-04-22 19:30:09 +02:00
}
2016-03-03 16:50:37 +01:00
// -> insert open URL
if ( multipleRows = = 1 & & ! url . isEmpty ( ) ) {
auto * openUrlAction = new QAction ( QIcon : : fromTheme ( QStringLiteral ( " applications-internet " ) ) , tr ( " Open URL " ) , & contextMenu ) ;
connect ( openUrlAction , & QAction : : triggered , bind ( & QDesktopServices : : openUrl , url ) ) ;
contextMenu . addAction ( openUrlAction ) ;
}
2015-04-22 19:30:09 +02:00
contextMenu . exec ( QCursor : : pos ( ) ) ;
}
/*!
* \ brief Copies the selected cells to the clipboard and clears the clipboard after \ a x milli seconds again .
*/
void MainWindow : : copyFieldsForXMilliSeconds ( int x )
{
QString text = selectedFieldsString ( ) ;
if ( ! text . isEmpty ( ) ) {
if ( m_clearClipboardTimer ) {
killTimer ( m_clearClipboardTimer ) ;
}
QApplication : : clipboard ( ) - > setText ( text ) ;
if ( x > 0 ) {
m_clearClipboardTimer = startTimer ( x , Qt : : CoarseTimer ) ;
}
} else {
QMessageBox : : warning ( this , QApplication : : applicationName ( ) , tr ( " The selection is empty. " ) ) ;
}
}
}