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