Import 0.4.3 version in mainstream branch
[keepassx] / src / mainwindow.cpp
1 /***************************************************************************
2  *   Copyright (C) 2005-2007 by Tarek Saidi                                *
3  *   tarek.saidi@arcor.de                                                  *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; version 2 of the License.               *
8  *                                                                         *
9  *   This program is distributed in the hope that it will be useful,       *
10  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
12  *   GNU General Public License for more details.                          *
13  *                                                                         *
14  *   You should have received a copy of the GNU General Public License     *
15  *   along with this program; if not, write to the                         *
16  *   Free Software Foundation, Inc.,                                       *
17  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
18  ***************************************************************************/
19
20 #include <QPointer>
21 #include <QToolBar>
22 #include <QStatusBar>
23 #include "mainwindow.h"
24 #include "lib/AutoType.h"
25 #include "import/Import_PwManager.h"
26 #include "import/Import_KWalletXml.h"
27 #include "import/Import_KeePassX_Xml.h"
28 #include "export/Export_Txt.h"
29 #include "export/Export_KeePassX_Xml.h"
30
31 #include "dialogs/AboutDlg.h"
32 #include "dialogs/SearchDlg.h"
33 #include "dialogs/SettingsDlg.h"
34 #include "dialogs/DatabaseSettingsDlg.h"
35 #include "dialogs/PasswordDlg.h"
36 #include "dialogs/SimplePasswordDlg.h"
37 #include "dialogs/PasswordGenDlg.h"
38 #include "dialogs/CollectEntropyDlg.h"
39 #include "dialogs/CustomizeDetailViewDlg.h"
40 #include "dialogs/ExpiredEntriesDlg.h"
41 //#include "dialogs/TrashCanDlg.h" //TODO TrashCan
42 #include "dialogs/AddBookmarkDlg.h"
43 #include "dialogs/ManageBookmarksDlg.h"
44 #include "dialogs/HelpDlg.h"
45
46 Import_KeePassX_Xml import_KeePassX_Xml;
47 Import_PwManager import_PwManager;
48 Import_KWalletXml import_KWalletXml;
49 Export_Txt export_Txt;
50 Export_KeePassX_Xml export_KeePassX_Xml;
51
52 KeepassMainWindow::KeepassMainWindow(const QString& ArgFile,bool ArgMin,bool ArgLock,QWidget *parent, Qt::WFlags flags) :QMainWindow(parent,flags){
53         ShutingDown=false;
54         IsLocked=false;
55         EventOccurred=true;
56         inactivityCounter=0;
57         InUnLock=false;
58         unlockDlg=NULL;
59         db=NULL;
60         setupUi(this);
61 #ifdef Q_WS_MAC
62         setUnifiedTitleAndToolBarOnMac(true);
63 #endif
64 #ifdef AUTOTYPE
65         initAutoType(this);
66 #endif
67 #ifdef GLOBAL_AUTOTYPE
68         autoType->registerGlobalShortcut(config->globalShortcut());
69 #endif
70         setWindowModified(false);
71         QByteArray windowGeo = config->mainWindowGeometry();
72         if (!windowGeo.isEmpty())
73                 restoreGeometry(windowGeo);
74         VSplitter->restoreState(config->vSplitterPos());
75         HSplitter->restoreState(config->hSplitterPos());
76         SysTray=new QSystemTrayIcon(this);
77         setupToolbar();
78         setupIcons();
79         setStateFileOpen(false);
80         setupMenus();
81         DetailView->setVisible(config->showEntryDetails());
82         StatusBarGeneral=new QLabel(statusBar());
83         //StatusBarSelection=new QLabel(statusBar());
84         statusBar()->addWidget(StatusBarGeneral,15);
85         //statusBar()->addWidget(StatusBarSelection,85);
86         statusBar()->setVisible(config->showStatusbar());
87         setStatusBarMsg(StatusBarReady);
88 #ifndef Q_WS_MAC
89         if (config->alwaysOnTop())
90                 setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
91 #endif
92
93         NormalCentralWidget=QMainWindow::centralWidget();
94         LockedCentralWidget=new QWidget(this);
95         WorkspaceLockedWidget.setupUi(LockedCentralWidget);
96         LockedCentralWidget->setVisible(false);
97
98         setupConnections();
99         connect(qApp, SIGNAL(commitDataRequest(QSessionManager&)), SLOT(OnShutdown(QSessionManager&)));
100         
101         inactivityTimer = new QTimer(this);
102         inactivityTimer->setInterval(500);
103         connect(inactivityTimer, SIGNAL(timeout()), SLOT(OnInactivityTimer()));
104         if (config->lockOnInactivity() && config->lockAfterSec()!=0)
105                 inactivityTimer->start();
106
107         bool showWindow = !ArgMin;
108         FileOpen=false;
109         if(!ArgFile.isEmpty()){
110                 QString f = QDir::cleanPath(QDir::current().absoluteFilePath(ArgFile));
111                 if (ArgLock)
112                         fakeOpenDatabase(f);
113                 else
114                         openDatabase(f,false);
115         }
116         else if(config->openLastFile() && !config->lastFile().isEmpty()){
117                 QFileInfo file(config->lastFile());
118                 if(file.exists()){
119                         QString f = QDir::cleanPath(QDir::current().absoluteFilePath(config->lastFile()));
120                         if (!ArgMin)
121                                 showWindow = !config->startMinimized();
122                         if (ArgLock || config->startLocked())
123                                 fakeOpenDatabase(f);
124                         else
125                                 openDatabase(f,true);
126                 }
127                 else
128                         config->setLastFile(QString());
129         }
130         
131         // TODO HelpBrowser
132         /*HelpBrowser = new QAssistantClient(QString(),this);
133         HelpBrowser->setArguments(QStringList()<< "-profile" << "share/keepass/doc/keepassx.adp");*/
134
135         createBookmarkActions();
136         
137         if (showWindow)
138                 show();
139         else if (!config->showSysTrayIcon())
140                 showMinimized();
141 }
142
143 void KeepassMainWindow::setupConnections(){
144         connect(FileNewAction, SIGNAL(triggered()), this, SLOT(OnFileNewKdb()));
145         connect(FileOpenAction, SIGNAL(triggered()), this, SLOT(OnFileOpen()));
146         connect(FileCloseAction, SIGNAL(triggered()), this, SLOT(OnFileClose()));
147         connect(FileSaveAction, SIGNAL(triggered()), this, SLOT(OnFileSave()));
148         connect(FileSaveAsAction, SIGNAL(triggered()), this, SLOT(OnFileSaveAs()));
149         connect(FileSettingsAction, SIGNAL(triggered()), this, SLOT(OnFileSettings()));
150         connect(FileChangeKeyAction, SIGNAL(triggered()), this, SLOT(OnFileChangeKey()));
151         connect(FileExitAction, SIGNAL(triggered()), this, SLOT(OnFileExit()));
152         connect(FileUnLockWorkspaceAction,SIGNAL(triggered()), this, SLOT(OnUnLockWorkspace()));
153         connect(menuImport,SIGNAL(triggered(QAction*)),this,SLOT(OnImport(QAction*)));
154         connect(menuExport,SIGNAL(triggered(QAction*)),this,SLOT(OnExport(QAction*)));
155         connect(menuBookmarks,SIGNAL(triggered(QAction*)),this,SLOT(OnBookmarkTriggered(QAction*)));
156
157         connect(EditNewGroupAction, SIGNAL(triggered()), GroupView, SLOT(OnNewGroup()));
158         connect(EditNewSubgroupAction, SIGNAL(triggered()), GroupView, SLOT(OnNewSubgroup()));
159         connect(EditEditGroupAction, SIGNAL(triggered()), GroupView, SLOT(OnEditGroup()));
160         connect(EditDeleteGroupAction, SIGNAL(triggered()), GroupView, SLOT(OnDeleteGroup()));
161         connect(EditGroupSortAction, SIGNAL(triggered()), GroupView, SLOT(OnSort()));
162         connect(EditNewEntryAction, SIGNAL(triggered()), EntryView, SLOT(OnNewEntry()));
163         connect(EditEditEntryAction, SIGNAL(triggered()), EntryView, SLOT(OnEditEntry()));
164         connect(EntryView, SIGNAL(requestCreateGroup(QString,quint32,GroupViewItem*)),
165                         GroupView, SLOT(createGroup(QString,quint32,GroupViewItem*)));
166         connect(EditCloneEntryAction, SIGNAL(triggered()), EntryView, SLOT(OnCloneEntry()));
167         connect(EditDeleteEntryAction, SIGNAL(triggered()), EntryView, SLOT(OnDeleteEntry()));
168         connect(EditUsernameToClipboardAction, SIGNAL(triggered()), EntryView, SLOT(OnUsernameToClipboard()));
169         connect(EditPasswordToClipboardAction, SIGNAL(triggered()), EntryView, SLOT(OnPasswordToClipboard()));
170         connect(EditOpenUrlAction, SIGNAL(triggered()), EntryView, SLOT(OnEditOpenUrl()));
171         connect(EditCopyUrlAction, SIGNAL(triggered()), EntryView, SLOT(OnEditCopyUrl()));
172         connect(EditSaveAttachmentAction, SIGNAL(triggered()),EntryView, SLOT(OnSaveAttachment()));
173         connect(EditSearchAction, SIGNAL(triggered()), this, SLOT(OnSearch()));
174         connect(EditGroupSearchAction, SIGNAL(triggered()), this, SLOT(OnGroupSearch()));
175 #ifdef AUTOTYPE
176         connect(EditAutoTypeAction,SIGNAL(triggered()),EntryView,SLOT(OnAutoType()));
177 #endif
178
179         connect(ViewShowToolbarAction,SIGNAL(toggled(bool)),this,SLOT(OnViewShowToolbar(bool)));
180         connect(ViewShowEntryDetailsAction,SIGNAL(toggled(bool)),this,SLOT(OnViewShowEntryDetails(bool)));
181         connect(ViewHidePasswordsAction,SIGNAL(toggled(bool)), this, SLOT(OnUsernPasswVisibilityChanged()));
182         connect(ViewHideUsernamesAction,SIGNAL(toggled(bool)), this, SLOT(OnUsernPasswVisibilityChanged()));
183
184         connect(menuColumns,SIGNAL(triggered(QAction*)),this,SLOT(OnColumnVisibilityChanged()));
185         connect(ViewToolButtonSize16Action,SIGNAL(toggled(bool)), this, SLOT(OnViewToolbarIconSize16(bool)));
186         connect(ViewToolButtonSize22Action,SIGNAL(toggled(bool)), this, SLOT(OnViewToolbarIconSize22(bool)));
187         connect(ViewToolButtonSize28Action,SIGNAL(toggled(bool)), this, SLOT(OnViewToolbarIconSize28(bool)));
188         connect(ViewShowStatusbarAction,SIGNAL(toggled(bool)),statusBar(),SLOT(setVisible(bool)));
189 #ifdef Q_WS_MAC
190         connect(ViewMinimizeAction, SIGNAL(triggered()), SLOT(showMinimized()));
191 #endif
192
193         connect(ExtrasSettingsAction,SIGNAL(triggered(bool)),this,SLOT(OnExtrasSettings()));
194         connect(ExtrasPasswordGenAction,SIGNAL(triggered(bool)),this,SLOT(OnExtrasPasswordGen()));
195         connect(ExtrasShowExpiredEntriesAction,SIGNAL(triggered(bool)),this,SLOT(OnExtrasShowExpiredEntries()));
196         //connect(ExtrasTrashCanAction,SIGNAL(triggered(bool)),this,SLOT(OnExtrasTrashCan())); //TODO ExtrasTrashCan
197
198         connect(HelpHandbookAction,SIGNAL(triggered()),this,SLOT(OnHelpHandbook()));
199         connect(HelpAboutAction,SIGNAL(triggered()),this,SLOT(OnHelpAbout()));
200
201         connect(QuickSearchEdit,SIGNAL(returnPressed()), this, SLOT(OnQuickSearch()));
202         connect(GroupView,SIGNAL(groupChanged(IGroupHandle*)),EntryView,SLOT(OnGroupChanged(IGroupHandle*)));
203         connect(GroupView,SIGNAL(groupChanged(IGroupHandle*)),this,SLOT(OnGroupSelectionChanged(IGroupHandle*)));
204         connect(GroupView,SIGNAL(fileModified()),this,SLOT(OnFileModified()));
205         connect(EntryView,SIGNAL(fileModified()),this,SLOT(OnFileModified()));
206         connect(EntryView,SIGNAL(selectionChanged(SelectionState)),this,SLOT(OnEntryChanged(SelectionState)));
207         connect(GroupView,SIGNAL(searchResultsSelected()),EntryView,SLOT(OnShowSearchResults()));
208         connect(GroupView,SIGNAL(searchResultsSelected()),this,SLOT(OnShowSearchResults()));
209         connect(GroupView,SIGNAL(entriesDropped()),EntryView,SLOT(removeDragItems()));
210         connect(HideSearchResultsAction,SIGNAL(triggered()),GroupView,SLOT(OnHideSearchResults()));
211         connect(EntryView, SIGNAL(viewModeChanged(bool)), SLOT(loadColumnVisibility()));
212         connect(EntryView, SIGNAL(viewModeChanged(bool)), ViewColumnsGroupAction, SLOT(setVisible(bool)));
213
214         connect(SysTray,SIGNAL(activated(QSystemTrayIcon::ActivationReason)),this,SLOT(OnSysTrayActivated(QSystemTrayIcon::ActivationReason)));
215         connect(DetailView,SIGNAL(anchorClicked(const QUrl&)),this,SLOT(OnDetailViewUrlClicked(const QUrl&)));
216         connect(WorkspaceLockedWidget.Button_Unlock,SIGNAL(clicked()),this,SLOT(OnUnLockWorkspace()));
217         connect(WorkspaceLockedWidget.Button_CloseDatabase,SIGNAL(clicked()),this,SLOT(OnLockClose()));
218 }
219
220 void KeepassMainWindow::setupToolbar(){
221         toolBar=new QToolBar(this);
222         toolBar->setMovable(false);
223         addToolBar(toolBar);
224         toolBar->setIconSize(QSize(config->toolbarIconSize(),config->toolbarIconSize()));
225         ViewShowToolbarAction=toolBar->toggleViewAction();
226         toolBar->addAction(FileNewAction);
227         toolBar->addAction(FileOpenAction);
228         toolBar->addAction(FileSaveAction);
229         toolBar->addSeparator();
230         toolBar->addAction(EditNewEntryAction);
231         toolBar->addAction(EditEditEntryAction);
232         toolBar->addAction(EditDeleteEntryAction);
233         toolBar->addSeparator();
234         toolBar->addAction(EditUsernameToClipboardAction);
235         toolBar->addAction(EditPasswordToClipboardAction);
236         toolBar->addSeparator();
237         toolBar->addAction(FileUnLockWorkspaceAction);
238         toolBar->addSeparator();
239         QuickSearchEdit=new QLineEdit(toolBar);
240         QuickSearchEdit->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed);
241         toolBar->addWidget(QuickSearchEdit);
242         toolBar->setVisible(config->showToolbar());
243 }
244
245 void KeepassMainWindow::setupIcons(){
246         setWindowIcon(getIcon("keepassx_small"));
247         FileNewAction->setIcon(getIcon("filenew"));
248         FileOpenAction->setIcon(getIcon("fileopen"));
249         FileSaveAction->setIcon(getIcon("filesave"));
250         FileSaveAsAction->setIcon(getIcon("filesaveas"));
251         FileCloseAction->setIcon(getIcon("fileclose"));
252         FileSettingsAction->setIcon(getIcon("dbsettings"));
253         FileUnLockWorkspaceAction->setIcon(getIcon("lock"));
254         FileExitAction->setIcon(getIcon("exit"));
255         EditNewEntryAction->setIcon(getIcon("newentry"));
256         EditEditEntryAction->setIcon(getIcon("editentry"));
257         EditDeleteEntryAction->setIcon(getIcon("deleteentry"));
258         EditGroupSortAction->setIcon(getIcon("swap"));
259         EditUsernameToClipboardAction->setIcon(getIcon("copyusername"));
260         EditPasswordToClipboardAction->setIcon(getIcon("copypwd"));
261         EditCloneEntryAction->setIcon(getIcon("cloneentry"));
262         EditOpenUrlAction->setIcon(getIcon("openurl"));
263         EditSaveAttachmentAction->setIcon(getIcon("filesave"));
264         EditNewGroupAction->setIcon(getIcon("newgroup"));
265         EditNewSubgroupAction->setIcon(getIcon("newgroup"));
266         EditEditGroupAction->setIcon(getIcon("editgroup"));
267         EditDeleteGroupAction->setIcon(getIcon("deletegroup"));
268         EditSearchAction->setIcon(getIcon("dbsearch"));
269         EditGroupSearchAction->setIcon(getIcon("groupsearch"));
270         ExtrasShowExpiredEntriesAction->setIcon(getIcon("expired"));
271         ExtrasPasswordGenAction->setIcon(getIcon("generator"));
272         //ExtrasTrashCanAction->setIcon(getIcon("trashcan")); //TODO ExtrasTrashCan
273         ExtrasSettingsAction->setIcon(getIcon("appsettings"));
274 #ifdef AUTOTYPE
275         EditAutoTypeAction->setIcon(getIcon("autotype"));
276 #else
277         EditAutoTypeAction->setVisible(false);
278 #endif
279         HelpHandbookAction->setIcon(getIcon("manual"));
280         HelpAboutAction->setIcon(getIcon("help_about"));
281         menuBookmarks->menuAction()->setIcon(getIcon("bookmark_folder"));
282         AddThisAsBookmarkAction->setIcon(getIcon("bookmark_this"));
283         AddBookmarkAction->setIcon(getIcon("bookmark_add"));
284         ManageBookmarksAction->setIcon(getIcon("bookmark"));
285         SysTray->setIcon(getIcon("keepassx"));
286         if(config->showSysTrayIcon())
287                 SysTray->show();
288 }
289
290 void KeepassMainWindow::setupMenus(){
291         GroupView->ContextMenu->addAction(EditNewSubgroupAction);
292         GroupView->ContextMenu->addAction(EditEditGroupAction);
293         GroupView->ContextMenu->addAction(EditDeleteGroupAction);
294         GroupView->ContextMenu->addAction(EditGroupSortAction);
295         GroupView->ContextMenu->addSeparator();
296         GroupView->ContextMenu->addAction(EditNewEntryAction);
297         GroupView->ContextMenu->addSeparator();
298         GroupView->ContextMenu->addAction(EditGroupSearchAction);
299         GroupView->ContextMenuSearchGroup->addAction(HideSearchResultsAction);
300
301         EntryView->ContextMenu->addAction(EditUsernameToClipboardAction);
302         EntryView->ContextMenu->addAction(EditPasswordToClipboardAction);
303         EntryView->ContextMenu->addAction(EditOpenUrlAction);
304         EntryView->ContextMenu->addAction(EditCopyUrlAction);
305         EntryView->ContextMenu->addAction(EditSaveAttachmentAction);
306 #ifdef AUTOTYPE
307         EntryView->ContextMenu->addAction(EditAutoTypeAction);
308 #endif
309         EntryView->ContextMenu->addSeparator();
310         EntryView->ContextMenu->addAction(EditNewEntryAction);
311         EntryView->ContextMenu->addAction(EditEditEntryAction);
312         EntryView->ContextMenu->addAction(EditCloneEntryAction);
313         EntryView->ContextMenu->addAction(EditDeleteEntryAction);
314
315         ViewShowToolbarAction->setText(tr("Show &Toolbar"));
316         ViewMenu->insertAction(ViewShowEntryDetailsAction,ViewShowToolbarAction);
317         ViewShowToolbarAction->setChecked(config->showToolbar());
318         ViewShowEntryDetailsAction->setChecked(config->showEntryDetails());
319         ViewHidePasswordsAction->setChecked(config->hidePasswords());
320         ViewHideUsernamesAction->setChecked(config->hideUsernames());
321         loadColumnVisibility();
322         ViewShowStatusbarAction->setChecked(config->showStatusbar());
323
324         switch(config->toolbarIconSize()){
325                 case 16: ViewToolButtonSize16Action->setChecked(true); break;
326                 case 22: ViewToolButtonSize22Action->setChecked(true); break;
327                 case 28: ViewToolButtonSize28Action->setChecked(true); break;
328         }
329         
330 #ifdef Q_WS_MAC
331         ViewMenu->addSeparator();
332         ViewMenu->addAction(ViewMinimizeAction);
333 #endif
334
335         SysTrayMenu = new QMenu(APP_DISPLAY_NAME,this);
336         SysTrayMenu->addAction(FileUnLockWorkspaceAction);
337         SysTrayMenu->addSeparator();
338         SysTrayMenu->addAction(FileExitAction);
339         SysTray->setContextMenu(SysTrayMenu);
340         updateTrayTooltip();
341
342         #define _add_import(name){\
343         QAction* import=new QAction(this);\
344         import->setData(qVariantFromValue(dynamic_cast<QObject*>(&name)));\
345         import->setText(name.title());\
346         menuImport->addAction(import);}
347
348         #define _add_export(name){\
349         QAction* Export=new QAction(this);\
350         Export->setData(qVariantFromValue(dynamic_cast<QObject*>(&name)));\
351         Export->setText(name.title());\
352         menuExport->addAction(Export);}
353
354         _add_import(import_KeePassX_Xml)
355         _add_import(import_PwManager)
356         _add_import(import_KWalletXml)
357         _add_export(export_Txt);
358         _add_export(export_KeePassX_Xml);
359
360         FileNewAction->setShortcut(tr("Ctrl+N"));
361         FileOpenAction->setShortcut(tr("Ctrl+O"));
362         FileCloseAction->setShortcut(tr("Ctrl+W"));
363         FileSaveAction->setShortcut(tr("Ctrl+S"));
364         FileUnLockWorkspaceAction->setShortcut(tr("Ctrl+L"));
365         FileExitAction->setShortcut(tr("Ctrl+Q"));
366         EditNewGroupAction->setShortcut(tr("Ctrl+G"));
367         EditPasswordToClipboardAction->setShortcut(tr("Ctrl+C"));
368         EditUsernameToClipboardAction->setShortcut(tr("Ctrl+B"));
369         EditOpenUrlAction->setShortcut(tr("Ctrl+U"));
370         EditCopyUrlAction->setShortcut(tr("Ctrl+I"));
371         EditNewEntryAction->setShortcut(tr("Ctrl+Y"));
372         EditEditEntryAction->setShortcut(tr("Ctrl+E"));
373         EditDeleteEntryAction->setShortcut(tr("Ctrl+D"));
374         EditCloneEntryAction->setShortcut(tr("Ctrl+K"));
375         EditSearchAction->setShortcut(tr("Ctrl+F"));
376         ExtrasPasswordGenAction->setShortcut(tr("Ctrl+P"));
377         ExtrasShowExpiredEntriesAction->setShortcut(tr("Ctrl+X"));
378 #ifdef AUTOTYPE
379         EditAutoTypeAction->setShortcut(tr("Ctrl+V"));
380 #endif
381 #ifdef Q_WS_MAC
382         FileSaveAsAction->setShortcut(tr("Shift+Ctrl+S"));
383         EditGroupSearchAction->setShortcut(tr("Shift+Ctrl+F"));
384         ViewMinimizeAction->setShortcut(tr("Ctrl+M"));
385 #endif
386
387         //ExtrasTrashCanAction->setVisible(false); //TODO For KP 2.x only
388         menuBookmarks->menuAction()->setVisible(config->featureBookmarks());
389 }
390
391 void KeepassMainWindow::loadColumnVisibility() {
392         ViewColumnsTitleAction->setChecked(EntryView->columnVisible(0));
393         ViewColumnsUsernameAction->setChecked(EntryView->columnVisible(1));
394         ViewColumnsUrlAction->setChecked(EntryView->columnVisible(2));
395         ViewColumnsPasswordAction->setChecked(EntryView->columnVisible(3));
396         ViewColumnsCommentAction->setChecked(EntryView->columnVisible(4));
397         ViewColumnsExpireAction->setChecked(EntryView->columnVisible(5));
398         ViewColumnsCreationAction->setChecked(EntryView->columnVisible(6));
399         ViewColumnsLastChangeAction->setChecked(EntryView->columnVisible(7));
400         ViewColumnsLastAccessAction->setChecked(EntryView->columnVisible(8));
401         ViewColumnsAttachmentAction->setChecked(EntryView->columnVisible(9));
402         ViewColumnsGroupAction->setChecked(EntryView->columnVisible(10));
403 }
404
405 void KeepassMainWindow::setupDatabaseConnections(IDatabase* DB){
406         ICustomIcons* CustomIconsDb=dynamic_cast<ICustomIcons*>(DB);
407         if(CustomIconsDb){
408                 connect(CustomIconsDb,SIGNAL(iconsModified()),this,SLOT(OnFileModified()));
409                 connect(CustomIconsDb,SIGNAL(iconsModified()),EntryView,SLOT(updateIcons()));
410                 connect(CustomIconsDb,SIGNAL(iconsModified()),GroupView,SLOT(updateIcons()));
411         }
412 }
413
414
415 bool KeepassMainWindow::openDatabase(QString filename,bool IsAuto){
416         if (!QFile::exists(filename)){
417                 QMessageBox::critical(this, tr("Error"), tr("The database file does not exist."));
418                 return false;
419         }
420         
421         dbReadOnly = false;
422         
423         if (QFile::exists(filename+".lock")){
424                 QMessageBox msgBox(this);
425                 msgBox.setIcon(QMessageBox::Question);
426                 msgBox.setWindowTitle(tr("Database locked"));
427                 msgBox.setText(tr("The database you are trying to open is locked.\n"
428                                 "This means that either someone else has opened the file or KeePassX crashed last time it opened the database.\n\n"
429                                 "Do you want to open it anyway?"
430                 ));
431                 msgBox.addButton(QMessageBox::Yes);
432                 msgBox.addButton(QMessageBox::No);
433                 QPushButton* readOnlyButton = new QPushButton(tr("Open read-only"), &msgBox);
434                 msgBox.addButton(readOnlyButton, QMessageBox::AcceptRole);
435                 msgBox.setDefaultButton(readOnlyButton);
436                 msgBox.exec();
437                 
438                 if (!msgBox.clickedButton() || msgBox.clickedButton() == msgBox.button(QMessageBox::No))
439                         return false;
440                 else if (msgBox.clickedButton() == readOnlyButton)
441                         dbReadOnly = true;
442         }
443         
444         if(!IsAuto){
445                 config->setLastKeyLocation(QString());
446                 config->setLastKeyType(PASSWORD);
447         }
448         db = new Kdb3Database();
449         PasswordDialog::DlgFlags flags=PasswordDialog::Flag_None;
450         if(IsAuto)
451                 flags = PasswordDialog::Flag_Auto;
452         PasswordDialog dlg(this,PasswordDialog::Mode_Ask,flags,filename);
453         if (InUnLock){
454                 dlg.setWindowModality(Qt::WindowModal);
455                 unlockDlg = &dlg;
456         }
457         bool rejected = (dlg.exec()==PasswordDialog::Exit_Cancel);
458         if (InUnLock)
459                 unlockDlg = NULL;
460         if (rejected)
461                 return false;
462         
463         if(dlg.selectedBookmark()!=QString())
464                 filename=dlg.selectedBookmark();
465
466         GroupView->db=db;
467         EntryView->db=db;
468         setupDatabaseConnections(db);
469         QString err;
470         setStatusBarMsg(StatusBarLoading);
471         db->setKey(dlg.password(),dlg.keyFile());
472         
473         if (!dbReadOnly && !QFile::exists(filename+".lock")){
474                 QFile lock(filename+".lock");
475                 if (!lock.open(QIODevice::WriteOnly)){
476                         setStatusBarMsg(StatusBarReadOnlyLock);
477                         dbReadOnly = true;
478                 }
479         }
480         
481         if(db->load(filename, dbReadOnly)){
482                 if (IsLocked)
483                         resetLock();
484                 updateCurrentFile(filename);
485                 saveLastFilename(filename);
486                 GroupView->createItems();
487                 EntryView->showGroup(NULL);
488                 setStateFileOpen(true);
489                 setStateFileModified(static_cast<Kdb3Database*>(db)->hasPasswordEncodingChanged());
490         }
491         else{
492                 if (!dbReadOnly && QFile::exists(filename+".lock"))
493                         QFile::remove(filename+".lock");
494                 setStatusBarMsg(StatusBarLoadingFailed);
495                 QString error=db->getError();
496                 if(error.isEmpty())error=tr("Unknown error while loading database.");
497                 QMessageBox::critical(this,tr("Error"),
498                                       QString("%1\n%2").arg(tr("The following error occured while opening the database:"))
499                                       .arg(error));
500                 if(db->isKeyError()){
501                         delete db;
502                         return openDatabase(filename,IsAuto);
503                 }
504                 else{
505                         delete db;
506                         return false;
507                 }
508         }
509         if (statusbarState != StatusBarReadOnlyLock)
510                 setStatusBarMsg(StatusBarReady);
511         inactivityCounter = 0;
512         
513         GroupView->selectFirstGroup();
514         
515         return true;
516 }
517
518 void KeepassMainWindow::fakeOpenDatabase(const QString& filename){
519         if (!QFile::exists(filename)){
520                 QMessageBox::critical(this, tr("Error"), tr("The database file does not exist."));
521                 return;
522         }
523         
524         config->setLastFile(filename);
525         updateCurrentFile(filename);
526         setLock();
527 }
528
529 bool KeepassMainWindow::closeDatabase(bool lock){
530         Q_ASSERT(FileOpen);
531         Q_ASSERT(db!=NULL);
532         if(ModFlag){
533                 if(config->autoSave() && db->file()){
534                         if(!OnFileSave()) return false;
535                 }
536                 else{
537                         QMessageBox::StandardButton r=QMessageBox::question(this,tr("Save modified file?"),
538                                                         tr("The current file was modified.\nDo you want to save the changes?"),
539                                                         QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel, QMessageBox::Yes);
540                         if(r==QMessageBox::Cancel) return false; //Cancel
541                         if(r==QMessageBox::Yes){ //Yes (Save file)
542                                 if (dbReadOnly) {
543                                         if(!OnFileSaveAs()) return false;
544                                 }
545                                 else {
546                                         if(!OnFileSave()) return false;
547                                 }
548                         }
549                 }
550         }
551         db->close();
552         delete db;
553         db=NULL;
554         if (!dbReadOnly && QFile::exists(currentFilePath+".lock")){
555                 if (!QFile::remove(currentFilePath+".lock"))
556                         QMessageBox::critical(this, tr("Error"), tr("Couldn't remove database lock file."));
557         }
558         EntryView->db=NULL;
559         EntryView->clear();
560         EntryView->Items.clear();
561         GroupView->db=NULL;
562         GroupView->clear();
563         GroupView->Items.clear();
564         SearchResults.clear();
565         if (lock)
566                 IsLocked = true;
567         setStateFileOpen(false);
568         if (!lock){
569                 updateCurrentFile(QString());
570                 QuickSearchEdit->setText("");
571                 updateTrayTooltip();
572         }
573         return true;
574 }
575
576
577 void KeepassMainWindow::OnFileNewKdb(){
578         IDatabase* db_new=dynamic_cast<IDatabase*>(new Kdb3Database());
579         db_new->create();
580         PasswordDialog dlg(this,PasswordDialog::Mode_Set,PasswordDialog::Flag_None,"New Database");
581         if(dlg.exec()==PasswordDialog::Exit_Ok){
582                 if(FileOpen)
583                         if(!closeDatabase())return;
584                 if (IsLocked)
585                         resetLock();
586                 db=db_new;
587                 db->setKey(dlg.password(),dlg.keyFile());
588                 db->generateMasterKey();
589                 updateCurrentFile(QString());
590                 GroupView->db=db;
591                 EntryView->db=db;
592                 GroupView->createItems();
593                 EntryView->showGroup(NULL);
594                 setStateFileOpen(true);
595                 setStateFileModified(true);
596                 setupDatabaseConnections(db);
597                 setStateGroupSelected(NONE);
598                 setStateEntrySelected(NONE);
599                 GroupView->createGroup("Internet", 1);
600                 GroupView->createGroup("eMail", 19);
601         }
602         else{
603                 delete db_new;
604         }
605 }
606
607 void KeepassMainWindow::openFile(const QString& filename) {
608         if(FileOpen) {
609                 if(!closeDatabase())
610                         return;
611         }
612         openDatabase(filename);
613 }
614
615 void KeepassMainWindow::OnFileOpen(){
616         /*QFileDialog FileDlg(this,tr("Open Database..."),QDir::homePath());
617         FileDlg.setFilters(QStringList()<< tr("KeePass Databases (*.kdb)")<< tr("All Files (*)"));
618         FileDlg.setFileMode(QFileDialog::ExistingFile);
619         FileDlg.setAcceptMode(QFileDialog::AcceptOpen);
620         if(!FileDlg.exec())return;
621         if(!FileDlg.selectedFiles().size())return;*/
622         QString filename=KpxFileDialogs::openExistingFile(this,"MainWindow_FileOpen",
623                         tr("Open Database..."),QStringList()<<tr("KeePass Databases (*.kdb)")<< tr("All Files (*)"));
624         if (!filename.isEmpty())
625                 openFile(filename);
626 }
627
628 void KeepassMainWindow::OnFileClose(){
629         if (IsLocked)
630                 OnLockClose();
631         else
632                 closeDatabase();
633 }
634
635 void KeepassMainWindow::setStateFileOpen(bool IsOpen){
636         FileOpen=IsOpen;
637         FileSaveAction->setEnabled(IsOpen);
638         FileSaveAsAction->setEnabled(IsOpen);
639         FileCloseAction->setEnabled(IsOpen||IsLocked);
640         FileSettingsAction->setEnabled(IsOpen);
641         FileChangeKeyAction->setEnabled(IsOpen);
642         menuExport->setEnabled(IsOpen);
643         EditNewGroupAction->setEnabled(IsOpen);
644         EditSearchAction->setEnabled(IsOpen);
645         GroupView->setEnabled(IsOpen);
646         EntryView->setEnabled(IsOpen);
647         DetailView->setEnabled(IsOpen);
648         QuickSearchEdit->setEnabled(IsOpen);
649         ExtrasShowExpiredEntriesAction->setEnabled(IsOpen);
650         AddThisAsBookmarkAction->setEnabled(IsOpen && db->file());
651         FileUnLockWorkspaceAction->setEnabled(IsOpen||IsLocked);
652         
653         if(!IsOpen){
654                 EditNewSubgroupAction->setEnabled(false);
655                 EditEditGroupAction->setEnabled(false);
656                 EditDeleteGroupAction->setEnabled(false);
657                 EditPasswordToClipboardAction->setEnabled(false);
658                 EditUsernameToClipboardAction->setEnabled(false);
659                 EditOpenUrlAction->setEnabled(false);
660                 EditCopyUrlAction->setEnabled(false);
661                 EditSaveAttachmentAction->setEnabled(false);
662                 EditNewEntryAction->setEnabled(false);
663                 EditEditEntryAction->setEnabled(false);
664                 EditCloneEntryAction->setEnabled(false);
665                 EditDeleteEntryAction->setEnabled(false);
666                 EditGroupSearchAction->setEnabled(false);
667 #ifdef AUTOTYPE
668                 EditAutoTypeAction->setEnabled(false);
669 #endif
670         }
671         
672         updateWindowTitle();
673         updateTrayTooltip();
674 }
675
676
677 void KeepassMainWindow::setStateFileModified(bool mod){
678         if (config->autoSaveChange() && mod && db->file()){
679                 if (OnFileSave())
680                         return; // return on success, so we don't set the state to modified
681         }
682         
683         ModFlag=mod;
684         if(mod)
685                 FileSaveAction->setIcon(getIcon("filesave"));
686         else
687                 FileSaveAction->setIcon(getIcon("filesavedisabled"));
688         updateWindowTitle();
689         setWindowModified(mod);
690 }
691
692 void KeepassMainWindow::setStateGroupSelected(SelectionState s){
693         GroupSelection=s;
694         switch(GroupSelection){
695                 case NONE:
696                         EditNewSubgroupAction->setEnabled(false);
697                         EditEditGroupAction->setEnabled(false);
698                         EditDeleteGroupAction->setEnabled(false);
699                         EditGroupSearchAction->setEnabled(false);
700                         EditNewEntryAction->setEnabled(false);
701                         break;
702                 case SINGLE:
703                         EditNewSubgroupAction->setEnabled(true);
704                         EditEditGroupAction->setEnabled(true);
705                         EditDeleteGroupAction->setEnabled(true);
706                         EditGroupSearchAction->setEnabled(true);
707                         EditNewEntryAction->setEnabled(true);
708                         break;
709                 case SEARCHGROUP:
710                         EditNewSubgroupAction->setEnabled(false);
711                         EditEditGroupAction->setEnabled(false);
712                         EditDeleteGroupAction->setEnabled(false);
713                         EditGroupSearchAction->setEnabled(false);
714                         EditNewEntryAction->setEnabled(false);
715                         break;
716                 default: Q_ASSERT(false);
717         }
718 }
719
720 void KeepassMainWindow::updateDetailView(){
721         if(EntryView->selectedItems().size()!=1){
722                 DetailView->setPlainText("");
723                 return;
724         }
725
726         QString templ=DetailViewTemplate;
727         IEntryHandle* entry=((EntryViewItem*)(EntryView->selectedItems()[0]))->EntryHandle;
728
729         templ.replace("%group%", Qt::escape(entry->group()->title()));
730         templ.replace("%title%", Qt::escape(entry->title()));
731         if (config->hideUsernames())
732                 templ.replace("%username%","****");
733         else
734                 templ.replace("%username%", Qt::escape(entry->username()));
735         if (!config->hidePasswords()) {
736                 SecString password=entry->password();
737                 password.unlock();
738                 templ.replace("%password%", Qt::escape(password.string()));
739         }
740         else {
741                 templ.replace("%password%","****");
742         }
743         templ.replace("%url%", Qt::escape(entry->url()));
744         templ.replace("%creation%", Qt::escape(entry->creation().toString(Qt::SystemLocaleDate)));
745         templ.replace("%lastmod%", Qt::escape(entry->lastMod().toString(Qt::SystemLocaleDate)));
746         templ.replace("%lastaccess%", Qt::escape(entry->lastAccess().toString(Qt::SystemLocaleDate)));
747         templ.replace("%expire%", Qt::escape(entry->expire().toString(Qt::SystemLocaleDate)));
748         templ.replace("%comment%", Qt::escape(entry->comment()).replace("\n","<br/>"));
749         templ.replace("%attachment%", Qt::escape(entry->binaryDesc()));
750
751         if(entry->expire()!=Date_Never){
752                 int secs=QDateTime::currentDateTime().secsTo(entry->expire());
753                 if(secs < 0)
754                         templ.replace("%expire-timeleft%",tr("Expired"));
755                 else{
756                         int years=0;
757                         int months=0;
758                         int days=0;
759                         years=secs/(86400*365);
760                         secs-=years*(86400*365);
761                         months=secs/(86400*30);
762                         secs-=months*(86400*30);
763                         days=secs/86400;
764
765                         QString out;
766
767                         if(months==1)
768                                 out=tr("1 Month");
769                         if(months>1)
770                                 out=tr("%1 Months").arg(months);
771
772                         if(years){
773                                 if(out!=QString())
774                                         out.prepend(", ");
775                                 if(years==1)
776                                         out.prepend(tr("1 Year"));
777                                 if(years>1)
778                                         out.prepend(tr("%1 Years").arg(years));
779                         }
780                         else if(days){
781                                 if(out!=QString())
782                                         out.append(", ");
783                                 if(days==1)
784                                         out.append(tr("1 Day"));
785                                 if(days>1)
786                                         out.append(tr("%1 Days").arg(days));
787                         }
788
789                         if(!days && !years && !months)
790                                 out=tr("less than 1 day");
791
792                         templ.replace("%expire-timeleft%","in " + out);
793                 }
794         }
795         else
796                 templ.replace("%expire-timeleft%","-");
797
798         DetailView->setHtml(templ);
799 }
800
801
802 void KeepassMainWindow::setStateEntrySelected(SelectionState s){
803         EntrySelection = s;
804         if (GroupSelection == NONE || GroupSelection == SINGLE){
805                 switch (EntrySelection){
806                         case NONE:
807                                 EditPasswordToClipboardAction->setEnabled(false);
808                                 EditUsernameToClipboardAction->setEnabled(false);
809                                 EditOpenUrlAction->setEnabled(false);
810                                 EditCopyUrlAction->setEnabled(false);
811                                 EditSaveAttachmentAction->setEnabled(false);
812                                 EditEditEntryAction->setEnabled(false);
813                                 EditCloneEntryAction->setEnabled(false);
814                                 EditCloneEntryAction->setText(tr("Clone Entry"));
815                                 EditDeleteEntryAction->setEnabled(false);
816                                 EditDeleteEntryAction->setText(tr("Delete Entry"));
817 #ifdef AUTOTYPE
818                                 EditAutoTypeAction->setEnabled(false);
819 #endif
820                                 break;
821                         case SINGLE:
822                                 EditPasswordToClipboardAction->setEnabled(true);
823                                 EditUsernameToClipboardAction->setEnabled(true);
824                                 EditOpenUrlAction->setEnabled(true);
825                                 EditCopyUrlAction->setEnabled(true);
826                                 EditSaveAttachmentAction->setEnabled(((EntryViewItem*)(EntryView->selectedItems()[0]))->EntryHandle->binarySize() > 0);
827                                 EditEditEntryAction->setEnabled(true);
828                                 EditCloneEntryAction->setEnabled(true);
829                                 EditCloneEntryAction->setText(tr("Clone Entry"));
830                                 EditDeleteEntryAction->setEnabled(true);
831                                 EditDeleteEntryAction->setText(tr("Delete Entry"));
832 #ifdef AUTOTYPE
833                                 EditAutoTypeAction->setEnabled(true);
834 #endif
835                                 break;
836                         case MULTIPLE:
837                                 EditPasswordToClipboardAction->setEnabled(false);
838                                 EditUsernameToClipboardAction->setEnabled(false);
839                                 EditOpenUrlAction->setEnabled(false);
840                                 EditCopyUrlAction->setEnabled(false);
841                                 EditSaveAttachmentAction->setEnabled(false);
842                                 EditEditEntryAction->setEnabled(false);
843                                 EditCloneEntryAction->setEnabled(true);
844                                 EditCloneEntryAction->setText(tr("Clone Entries"));
845                                 EditDeleteEntryAction->setEnabled(true);
846                                 EditDeleteEntryAction->setText(tr("Delete Entries"));
847 #ifdef AUTOTYPE
848                                 EditAutoTypeAction->setEnabled(false);
849 #endif
850                                 break;
851                         default:
852                                 Q_ASSERT(false);
853                 }
854         }
855         else if (GroupSelection == SEARCHGROUP){
856                 switch(EntrySelection){
857                         case NONE:
858                                 EditUsernameToClipboardAction->setEnabled(false);
859                                 EditPasswordToClipboardAction->setEnabled(false);
860                                 EditOpenUrlAction->setEnabled(false);
861                                 EditCopyUrlAction->setEnabled(false);
862                                 EditSaveAttachmentAction->setEnabled(false);
863                                 EditEditEntryAction->setEnabled(false);
864                                 EditCloneEntryAction->setEnabled(false);
865                                 EditCloneEntryAction->setText(tr("Clone Entry"));
866                                 EditDeleteEntryAction->setEnabled(false);
867                                 EditDeleteEntryAction->setText(tr("Delete Entry"));
868 #ifdef AUTOTYPE
869                                 EditAutoTypeAction->setEnabled(false);
870 #endif
871                                 break;
872                         case SINGLE:
873                                 EditUsernameToClipboardAction->setEnabled(true);
874                                 EditPasswordToClipboardAction->setEnabled(true);
875                                 EditOpenUrlAction->setEnabled(true);
876                                 EditCopyUrlAction->setEnabled(true);
877                                 EditSaveAttachmentAction->setEnabled(((EntryViewItem*)(EntryView->selectedItems()[0]))->EntryHandle->binarySize() > 0);
878                                 EditEditEntryAction->setEnabled(true);
879                                 EditCloneEntryAction->setEnabled(false);
880                                 EditCloneEntryAction->setText(tr("Clone Entry"));
881                                 EditDeleteEntryAction->setEnabled(true);
882                                 EditDeleteEntryAction->setText(tr("Delete Entry"));
883 #ifdef AUTOTYPE
884                                 EditAutoTypeAction->setEnabled(true);
885 #endif
886                                 break;
887                         case MULTIPLE:
888                                 EditUsernameToClipboardAction->setEnabled(false);
889                                 EditPasswordToClipboardAction->setEnabled(false);
890                                 EditOpenUrlAction->setEnabled(false);
891                                 EditCopyUrlAction->setEnabled(false);
892                                 EditSaveAttachmentAction->setEnabled(false);
893                                 EditEditEntryAction->setEnabled(false);
894                                 EditCloneEntryAction->setEnabled(false);
895                                 EditCloneEntryAction->setText(tr("Clone Entries"));
896                                 EditDeleteEntryAction->setEnabled(true);
897                                 EditDeleteEntryAction->setText(tr("Delete Entries"));
898 #ifdef AUTOTYPE
899                                 EditAutoTypeAction->setEnabled(false);
900 #endif
901                                 break;
902                         default:
903                                 Q_ASSERT(false);
904                 }
905         }
906         else
907                 Q_ASSERT(false);
908 }
909
910
911 bool KeepassMainWindow::OnFileSave(){
912         if(!db->file())
913                 return OnFileSaveAs();
914         saveLastFilename(db->file()->fileName());
915         if(db->save()){
916                 setStateFileOpen(true); // necessary for AddThisAsBookmarkAction
917                 setStateFileModified(false);
918                 if (config->backup() && config->backupDelete() && config->backupDeleteAfter()>0){
919                         IGroupHandle* backupGroup = db->backupGroup();
920                         if (backupGroup && backupGroup==EntryView->getCurrentGroup())
921                                 EntryView->showGroup(backupGroup);
922                 }
923                 return true;
924         }
925         else{
926                 showErrMsg(QString("%1\n%2").arg(tr("File could not be saved.")).arg(db->getError()));
927                 return false;
928         }
929 }
930
931 bool KeepassMainWindow::OnFileSaveAs(){
932         QString filename=KpxFileDialogs::saveFile(this,"MainWindow_FileSave",
933                         tr("Save Database..."),QStringList()<<tr("KeePass Databases (*.kdb)")<< tr("All Files (*)"));
934         if (filename.isEmpty() || filename.compare(".kdb", Qt::CaseInsensitive)==0)
935                 return false;
936         
937         QFile lock(filename+".lock");
938         if (!lock.open(QIODevice::WriteOnly)){
939                 QMessageBox::critical(this, tr("Error"), tr("Couldn't create database lock file."));
940                 return false;
941         }
942         
943         if(!db->changeFile(filename)){
944                 showErrMsg(QString("%1\n%2").arg(tr("File could not be saved.")).arg(db->getError()));
945                 QFile::remove( filename+".lock" );
946                 return false;
947         }
948         
949         if (!dbReadOnly && !currentFilePath.isEmpty() && QFile::exists(currentFilePath+".lock")){
950                 if (!QFile::remove(currentFilePath+".lock"))
951                         QMessageBox::critical(this, tr("Error"), tr("Couldn't remove database lock file."));
952         }
953         
954         dbReadOnly = false;
955         updateCurrentFile(filename);
956         updateWindowTitle();
957         updateTrayTooltip();
958         
959         return OnFileSave();
960 }
961
962 void KeepassMainWindow::OnFileSettings(){
963         CDbSettingsDlg dlg(this,db);
964         if(dlg.exec()){
965                 db->generateMasterKey();
966                 setStateFileModified(true);
967         }
968 }
969
970 void KeepassMainWindow::OnFileChangeKey(){
971         QFile* file=db->file();
972         QString filename = file ? file->fileName() : QString();
973         PasswordDialog dlg(this,PasswordDialog::Mode_Change,PasswordDialog::Flag_None,filename);
974         if(dlg.exec()==PasswordDialog::Exit_Ok){
975                 db->setKey(dlg.password(),dlg.keyFile());
976                 db->generateMasterKey();
977                 setStateFileModified(true);
978         }
979 }
980
981 void KeepassMainWindow::OnFileExit(){
982         ShutingDown = true;
983         close();
984 }
985
986
987 void KeepassMainWindow::OnExport(QAction* action){
988         dynamic_cast<IExport*>(action->data().value<QObject*>())->exportDatabase(this,db);
989 }
990
991 void KeepassMainWindow::OnImport(QAction* action){
992         if(FileOpen)
993                 if(!closeDatabase())return;
994         IDatabase* tmpdb=dynamic_cast<IDatabase*>(new Kdb3Database());
995         tmpdb->create();
996         if(dynamic_cast<IImport*>(action->data().value<QObject*>())->importDatabase(this,tmpdb)){
997                 PasswordDialog dlg(this,PasswordDialog::Mode_Set,PasswordDialog::Flag_None,QString());
998                 if(dlg.exec()!=PasswordDialog::Exit_Ok){
999                         delete tmpdb;
1000                         return;
1001                 }
1002                 db=tmpdb;
1003                 db->setKey(dlg.password(),dlg.keyFile());
1004                 db->generateMasterKey();
1005                 GroupView->db=db;
1006                 EntryView->db=db;
1007                 setupDatabaseConnections(db);
1008                 GroupView->createItems();
1009                 EntryView->showGroup(NULL);
1010                 setStateFileOpen(true);
1011                 setStateFileModified(true);
1012         }
1013         else
1014                 delete tmpdb;
1015 }
1016
1017 /*
1018 void KeepassMainWindow::removeFromSearchResults(int id){
1019 for(int i=0; i<SearchResults.size();i++){
1020  if(SearchResults[i]==id){
1021         SearchResults.removeAt(i);
1022         return;
1023  }
1024 }
1025 }
1026 */
1027
1028 void KeepassMainWindow::search(IGroupHandle* group){
1029         SearchDialog dlg(db,group,this);
1030         if(dlg.exec()){
1031                 EntryView->SearchResults=dlg.Result;
1032                 GroupView->showSearchResults();
1033         }
1034 }
1035
1036 void KeepassMainWindow::OnSearch(){
1037         search(NULL);
1038 }
1039
1040 void KeepassMainWindow::OnGroupSearch(){
1041         Q_ASSERT(GroupView->currentItem());
1042         search(((GroupViewItem*)GroupView->currentItem())->GroupHandle);
1043 }
1044
1045 void KeepassMainWindow::OnQuickSearch(){
1046         EntryView->SearchResults=db->search(NULL,QuickSearchEdit->text(),false,false,false,NULL);
1047         GroupView->showSearchResults();
1048 }
1049
1050 void KeepassMainWindow::OnColumnVisibilityChanged(){
1051         EntryView->setColumnVisible(0, ViewColumnsTitleAction->isChecked());
1052         EntryView->setColumnVisible(1, ViewColumnsUsernameAction->isChecked());
1053         EntryView->setColumnVisible(2, ViewColumnsUrlAction->isChecked());
1054         EntryView->setColumnVisible(3, ViewColumnsPasswordAction->isChecked());
1055         EntryView->setColumnVisible(4, ViewColumnsCommentAction->isChecked());
1056         EntryView->setColumnVisible(5, ViewColumnsExpireAction->isChecked());
1057         EntryView->setColumnVisible(6, ViewColumnsCreationAction->isChecked());
1058         EntryView->setColumnVisible(7, ViewColumnsLastChangeAction->isChecked());
1059         EntryView->setColumnVisible(8, ViewColumnsLastAccessAction->isChecked());
1060         EntryView->setColumnVisible(9, ViewColumnsAttachmentAction->isChecked());
1061         EntryView->setColumnVisible(10, ViewColumnsGroupAction->isVisible() && ViewColumnsGroupAction->isChecked());
1062 }
1063
1064 void KeepassMainWindow::OnUsernPasswVisibilityChanged(){
1065         config->setHidePasswords(ViewHidePasswordsAction->isChecked());
1066         config->setHideUsernames(ViewHideUsernamesAction->isChecked());
1067         EntryView->refreshItems();
1068 }
1069
1070 void KeepassMainWindow::OnFileModified(){
1071         setStateFileModified(true);
1072 }
1073
1074 void KeepassMainWindow::closeEvent(QCloseEvent* e){
1075         if (!ShutingDown && config->showSysTrayIcon() && config->minimizeToTray()){
1076                 e->ignore();
1077                 if (config->lockOnMinimize() && !IsLocked && FileOpen)
1078                         OnUnLockWorkspace();
1079                 hide();
1080                 return;
1081         }
1082         
1083         if(FileOpen && !closeDatabase()){
1084                 ShutingDown = false;
1085                 e->ignore();
1086                 if (!isVisible())
1087                         show();
1088                 return;
1089         }
1090         
1091         e->accept();
1092         
1093 #ifdef GLOBAL_AUTOTYPE
1094         autoType->unregisterGlobalShortcut();
1095 #endif
1096
1097         config->setMainWindowGeometry(saveGeometry());
1098         // workaround if window has never been visible
1099         if (isVisible() || VSplitter->sizes()[0]!=VSplitter->sizes()[1])
1100                 config->setVSplitterPos(VSplitter->saveState());
1101         if (config->showEntryDetails())
1102                 config->setHSplitterPos(HSplitter->saveState());
1103         config->setShowStatusbar(statusBar()->isVisible());
1104         
1105         delete SysTray;
1106         QMainWindow::closeEvent(e);
1107         QApplication::quit();
1108 }
1109
1110 void KeepassMainWindow::hideEvent(QHideEvent* event){
1111         if (event->spontaneous() && QApplication::activeModalWidget()==NULL){
1112                 if (config->lockOnMinimize() && !IsLocked && FileOpen)
1113                         OnUnLockWorkspace();
1114                 if (config->showSysTrayIcon() && config->minimizeTray()){
1115 #ifdef Q_WS_WIN
1116                         QTimer::singleShot(100, this, SLOT(hide()));
1117 #else
1118                         hide();
1119 #endif
1120                         event->accept();
1121                         return;
1122                 }
1123         }
1124         
1125         QMainWindow::hideEvent(event);
1126 }
1127
1128 void KeepassMainWindow::showEvent(QShowEvent* event){
1129         if (IsLocked && !InUnLock && event->spontaneous()){
1130 #ifndef Q_WS_MAC
1131                 showNormal(); // workaround for some graphic glitches
1132 #endif
1133                 OnUnLockWorkspace();
1134         }
1135         
1136         QMainWindow::showEvent(event);
1137 }
1138
1139 void KeepassMainWindow::OnExtrasSettings(){
1140         QString oldLang = config->language();
1141         bool oldAlwaysOnTop = config->alwaysOnTop();
1142         CSettingsDlg dlg(this);
1143         dlg.exec();
1144         if (config->language() != oldLang){
1145                 retranslateUi(this);
1146                 WorkspaceLockedWidget.retranslateUi(LockedCentralWidget);
1147                 ViewShowToolbarAction->setText(tr("Show &Toolbar"));
1148                 EntryView->retranslateColumns();
1149                 GroupView->retranslateUi();
1150                 updateWindowTitle();
1151                 updateTrayTooltip();
1152                 setStatusBarMsg(statusbarState);
1153         }
1154         
1155         EntryView->setAlternatingRowColors(config->alternatingRowColors());
1156         SysTray->setVisible(config->showSysTrayIcon());
1157         menuBookmarks->menuAction()->setVisible(config->featureBookmarks());
1158 #ifndef Q_WS_MAC
1159         if (config->alwaysOnTop() != oldAlwaysOnTop) {
1160                 if (config->alwaysOnTop())
1161                         setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
1162                 else
1163                         setWindowFlags(windowFlags() & ~Qt::WindowStaysOnTopHint);
1164                 show();
1165         }
1166 #endif
1167         
1168         EventOccurred = true;
1169         if (config->lockOnInactivity() && config->lockAfterSec()!=0 && !inactivityTimer->isActive()){
1170                 inactivityCounter = 0;
1171                 inactivityTimer->start();
1172         }
1173         else if ((!config->lockOnInactivity() || config->lockAfterSec()==0) && inactivityTimer->isActive()){
1174                 inactivityTimer->stop();
1175         }
1176 }
1177
1178 void KeepassMainWindow::OnHelpAbout(){
1179         AboutDialog dlg(this);
1180         dlg.exec();
1181 }
1182
1183 void KeepassMainWindow::OnHelpHandbook(){
1184         QPointer<HelpDlg> dlg = new HelpDlg(this);
1185         dlg->exec();
1186         delete dlg;
1187 }
1188
1189 void KeepassMainWindow::OnViewShowToolbar(bool show){
1190         config->setShowToolbar(show);
1191         toolBar->setVisible(show);
1192 }
1193
1194 void KeepassMainWindow::OnViewShowEntryDetails(bool show){
1195         config->setShowEntryDetails(show);
1196         DetailView->setVisible(show);
1197 }
1198
1199 /*void KeepassMainWindow::OnItemExpanded(QTreeWidgetItem* item){
1200 //((GroupViewItem*)item)->pGroup->UI_ItemIsExpanded=true;
1201 }
1202
1203 void KeepassMainWindow::OnItemCollaped(QTreeWidgetItem* item){
1204 //((GroupViewItem*)item)->pGroup->UI_ItemIsExpanded=false;
1205 }*/
1206
1207 void KeepassMainWindow::OnGroupSelectionChanged(IGroupHandle* group){
1208         if(group)
1209                 setStateGroupSelected(SINGLE);
1210         else
1211                 setStateGroupSelected(NONE);
1212 }
1213
1214 void KeepassMainWindow::OnEntryChanged(SelectionState Selection){
1215         updateDetailView();
1216         setStateEntrySelected(Selection);
1217 }
1218
1219 void KeepassMainWindow::OnShowSearchResults(){
1220         setStateGroupSelected(SEARCHGROUP);
1221 }
1222
1223
1224 void KeepassMainWindow::OnViewToolbarIconSize16(bool state){
1225         if(!state)return;
1226         ViewToolButtonSize22Action->setChecked(false);
1227         ViewToolButtonSize28Action->setChecked(false);
1228         config->setToolbarIconSize(16);
1229         toolBar->setIconSize(QSize(16,16));
1230 }
1231
1232 void KeepassMainWindow::OnViewToolbarIconSize22(bool state){
1233         if(!state)return;
1234         ViewToolButtonSize16Action->setChecked(false);
1235         ViewToolButtonSize28Action->setChecked(false);
1236         config->setToolbarIconSize(22);
1237         toolBar->setIconSize(QSize(22,22));
1238 }
1239
1240 void KeepassMainWindow::OnViewToolbarIconSize28(bool state){
1241         if(!state)return;
1242         ViewToolButtonSize16Action->setChecked(false);
1243         ViewToolButtonSize22Action->setChecked(false);
1244         config->setToolbarIconSize(28);
1245         toolBar->setIconSize(QSize(28,28));
1246 }
1247
1248 void KeepassMainWindow::OnSysTrayActivated(QSystemTrayIcon::ActivationReason reason){
1249         if(reason!=QSystemTrayIcon::Context){
1250                 if (isVisible()){
1251                         if (unlockDlg!=NULL)
1252                                 unlockDlg->reject();
1253                         else if (config->lockOnMinimize() && !IsLocked && FileOpen)
1254                                 OnUnLockWorkspace();
1255                         hide();
1256                 }
1257                 else{
1258 #ifdef Q_WS_WIN
1259                         QTimer::singleShot(100, this, SLOT(restoreWindow()));
1260 #else
1261                         restoreWindow();
1262 #endif
1263                 }
1264         }
1265 }
1266
1267 void KeepassMainWindow::restoreWindow(){
1268 #ifdef Q_WS_WIN
1269         if (windowState() & Qt::WindowMaximized)
1270                 showMaximized();
1271         else
1272                 showNormal();
1273 #else
1274         showNormal();
1275 #endif
1276         activateWindow();
1277         if (IsLocked)
1278                 OnUnLockWorkspace();
1279 }
1280
1281 void KeepassMainWindow::OnExtrasPasswordGen(){
1282         CGenPwDialog dlg(this,true);
1283         dlg.exec();
1284 }
1285
1286
1287 void KeepassMainWindow::saveLastFilename(const QString& filename){
1288
1289         if(config->openLastFile()){
1290                 if(config->saveRelativePaths()){
1291                         QString Path=filename.left(filename.lastIndexOf("/"));
1292                         Path=makePathRelative(Path,QDir::currentPath());
1293                         config->setLastFile(Path+filename.right(filename.length()-filename.lastIndexOf("/")-1));
1294                 }
1295                 else
1296                         config->setLastFile(filename);
1297         }
1298 }
1299
1300 void KeepassMainWindow::OnExtrasShowExpiredEntries(){
1301         ExpiredEntriesDialog dlg(this,db,db->expiredEntries());
1302         if(dlg.exec()==QDialog::Accepted){
1303                 GroupView->setCurrentGroup(dlg.SelectedEntry->group());
1304                 EntryView->setCurrentEntry(dlg.SelectedEntry);
1305         }
1306
1307 }
1308
1309 //TODO TrashCan
1310 /*void KeepassMainWindow::OnExtrasTrashCan(){
1311         TrashCanDialog dlg(this,db,db->expiredEntries());
1312         if(dlg.exec()==QDialog::Accepted){
1313
1314         }
1315
1316 }*/
1317
1318 void KeepassMainWindow::OnDetailViewUrlClicked(const QUrl& url){
1319         openBrowser(url.toString());
1320 }
1321
1322 void KeepassMainWindow::OnUnLockWorkspace(){
1323         if(IsLocked){
1324                 if (InUnLock) return;
1325                 InUnLock = true;
1326                 if ( openDatabase(currentFilePath,true) ){
1327                         QTreeWidgetItem* item = GroupView->invisibleRootItem();
1328                         if (lockGroup.size()>0){
1329                                 for (int i=0; i<lockGroup.size(); i++){
1330                                         item = item->child(lockGroup[i]);
1331                                         if (item==NULL) break;
1332                                 }
1333                                 if (item!=NULL)
1334                                         GroupView->setCurrentItem(item);
1335                                 lockGroup.clear();
1336                         }
1337                 }
1338                 InUnLock = false;
1339         }
1340         else {
1341                 QTreeWidgetItem* item = GroupView->currentItem();
1342                 bool root = false;
1343                 while (item!=NULL){
1344                         QTreeWidgetItem* parent = item->parent();
1345                         if (parent==NULL && !root) {
1346                                 parent = GroupView->invisibleRootItem();
1347                                 root = true;
1348                         }
1349                         if (parent!=NULL)
1350                                 lockGroup.prepend(parent->indexOfChild(item));
1351                         item = parent;
1352                 }
1353                 
1354                 if (closeDatabase(true)) {
1355                         setStateFileModified(false);
1356                         setLock();
1357                 }
1358                 else
1359                         lockGroup.clear();
1360         }
1361 }
1362
1363 void KeepassMainWindow::OnLockClose(){
1364         resetLock();
1365         setStateFileOpen(false);
1366 }
1367
1368 void KeepassMainWindow::setLock(){
1369         QuickSearchEdit->setEchoMode(QLineEdit::NoEcho);
1370         NormalCentralWidget->setVisible(false);
1371         NormalCentralWidget->setParent(NULL);
1372         setCentralWidget(LockedCentralWidget);
1373         LockedCentralWidget->setVisible(true);
1374         SysTray->setIcon(getIcon("keepassx_locked"));
1375         FileUnLockWorkspaceAction->setText(tr("Un&lock Workspace"));
1376         IsLocked=true;
1377         updateTrayTooltip();
1378         setStateFileOpen(false);
1379 }
1380
1381 void KeepassMainWindow::resetLock(){
1382         if (!InUnLock)
1383                 QuickSearchEdit->setText("");
1384         QuickSearchEdit->setEchoMode(QLineEdit::Normal);
1385         LockedCentralWidget->setVisible(false);
1386         LockedCentralWidget->setParent(NULL);
1387         setCentralWidget(NormalCentralWidget);
1388         NormalCentralWidget->setVisible(true);
1389         SysTray->setIcon(getIcon("keepassx"));
1390         FileUnLockWorkspaceAction->setText(tr("&Lock Workspace"));
1391         IsLocked=false;
1392         updateTrayTooltip();
1393 }
1394
1395 void KeepassMainWindow::OnInactivityTimer(){
1396         if (IsLocked || !FileOpen)
1397                 return;
1398         
1399         if (QApplication::activeModalWidget()!=NULL || EventOccurredBlock){
1400                 inactivityCounter = 0;
1401                 return;
1402         }
1403         
1404         if (EventOccurred){
1405                 inactivityCounter = 0;
1406                 EventOccurred = false;
1407         }
1408         else{
1409                 inactivityCounter++;
1410                 if (inactivityCounter*(inactivityTimer->interval()) >= config->lockAfterSec()*1000){
1411                         QWidget* popUpWidget = QApplication::activePopupWidget();
1412                         if (popUpWidget!=NULL)
1413                                 popUpWidget->hide();
1414                         OnUnLockWorkspace();
1415                 }
1416         }
1417 }
1418
1419 void KeepassMainWindow::OnShutdown(QSessionManager& manager) {
1420         ShutingDown = true;
1421         
1422         /* QApplication::commitData() only closes visible windows,
1423            so we need to manually close mainwindow if it's hidden */
1424         if (manager.allowsInteraction() && !isVisible()) {
1425                 close();
1426         }
1427 }
1428
1429 void KeepassMainWindow::OnBookmarkTriggered(QAction* action){
1430         if(action==AddBookmarkAction){
1431                 AddBookmarkDlg dlg(this);
1432                 if(dlg.exec()){
1433                         int id=dlg.ItemID;
1434                         QAction* action=new QAction(this);
1435                         action->setData(id);
1436                         action->setText(KpxBookmarks::title(id));
1437                         action->setIcon(getIcon("document"));
1438                         menuBookmarks->addAction(action);
1439                 }
1440         }
1441         else if(action==ManageBookmarksAction){
1442                 ManageBookmarksDlg dlg(this);
1443                 dlg.exec();
1444                 menuBookmarks->clear();
1445                 createBookmarkActions();
1446         }
1447         else if(action==AddThisAsBookmarkAction){
1448                 AddBookmarkDlg dlg(this,db->file()->fileName());
1449                 if(dlg.exec()){
1450                         int id=dlg.ItemID;
1451                         QAction* action=new QAction(this);
1452                         action->setData(id);
1453                         action->setText(KpxBookmarks::title(id));
1454                         action->setIcon(getIcon("document"));
1455                         menuBookmarks->addAction(action);
1456                 }
1457         }
1458         else {
1459                 openDatabase(KpxBookmarks::path(action->data().toInt()));
1460         }
1461 }
1462
1463 void KeepassMainWindow::createBookmarkActions(){
1464         menuBookmarks->addAction(AddBookmarkAction);
1465         menuBookmarks->addAction(AddThisAsBookmarkAction);
1466         menuBookmarks->addAction(ManageBookmarksAction);
1467         menuBookmarks->addSeparator();
1468         for(int i=0;i<KpxBookmarks::count();i++){
1469                 QAction* action=new QAction(this);
1470                 action->setData(i);
1471                 action->setText(KpxBookmarks::title(i));
1472                 action->setIcon(getIcon("document"));
1473                 menuBookmarks->addAction(action);
1474         }
1475 }
1476
1477 void KeepassMainWindow::setStatusBarMsg(StatusBarMsg statusBarMsg) {
1478         QString text;
1479         
1480         switch (statusBarMsg) {
1481                 case StatusBarReady:
1482                         text = tr("Ready");
1483                         break;
1484                 case StatusBarLoading:
1485                         text = tr("Loading Database...");
1486                         break;
1487                 case StatusBarLoadingFailed:
1488                         text = tr("Loading Failed");
1489                         break;
1490                 case StatusBarReadOnlyLock:
1491                         text = tr("Couldn't create lock file. Opening the database read-only.");
1492                         break;
1493         }
1494         
1495         statusbarState = statusBarMsg;
1496         StatusBarGeneral->setText(text);
1497 }
1498
1499 void KeepassMainWindow::updateWindowTitle() {
1500         if (!IsLocked && !FileOpen)
1501                 setWindowTitle( QString("%1 - %2").arg(APP_DISPLAY_NAME, APP_SHORT_FUNC) );
1502         else if (currentFilePath.isEmpty())
1503                 setWindowTitle( QString("[%1][*] - %2").arg(tr("new"), APP_DISPLAY_NAME) );
1504         else if (IsLocked)
1505                 setWindowTitle( QString("%1 (%2) - %3").arg(currentFilePath, tr("locked"), APP_DISPLAY_NAME) );
1506         else if (ModFlag)
1507                 setWindowTitle( QString("%1[*] - %2").arg(currentFilePath, APP_DISPLAY_NAME) );
1508         else
1509                 setWindowTitle( QString("%1 - %2").arg(currentFilePath, APP_DISPLAY_NAME) );
1510 }
1511
1512 void KeepassMainWindow::updateTrayTooltip() {
1513         if (!IsLocked && !FileOpen)
1514                 SysTray->setToolTip(QString("%1 - %2").arg(APP_DISPLAY_NAME, APP_SHORT_FUNC));
1515         else {
1516                 QString tooltip = QString("%1 - %2").arg(APP_DISPLAY_NAME, currentFilePath.isEmpty()
1517                                 ? QString("[%1]").arg(tr("new")) : currentFileName);
1518                 if (IsLocked)
1519                         tooltip.append( QString(" (%1)").arg(tr("locked")) );
1520                 SysTray->setToolTip(tooltip);
1521         }
1522 }
1523
1524 void KeepassMainWindow::updateCurrentFile(const QString& filePath) {
1525         currentFilePath = filePath;
1526         currentFileName = QFileInfo(filePath).fileName();
1527 }