diff --git a/trunk/dlgreportchooser.cpp b/trunk/dlgreportchooser.cpp index bb95439..5ab1bdf 100644 --- a/trunk/dlgreportchooser.cpp +++ b/trunk/dlgreportchooser.cpp @@ -1,148 +1,160 @@ /******************************************************************************* * fred Copyright (c) 2011-2013 by Gillen Daniel * * * * Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor * * with special feautures useful during forensic analysis. * * * * This program is free software: you can redistribute it and/or modify it * * under the terms of the GNU General Public License as published by the Free * * Software Foundation, either version 3 of the License, or (at your option) * * any later version. * * * * This program is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * *******************************************************************************/ #include "dlgreportchooser.h" #include "ui_dlgreportchooser.h" #include #include #include #include DlgReportChooser::DlgReportChooser(Reports *p_reps, QString hive_type_string, + Settings *p_sets, QWidget *p_parent) : QDialog(p_parent), ui(new Ui::DlgReportChooser) { QStringList tree_cats; QString cur_tree_cat; QTreeWidgetItem *p_tree_cat_widget; QTreeWidgetItem *p_tree_cat_rep_widget; QList tree_cat_reports; ReportTemplate* p_report; // Init private vars this->ui->setupUi(this); this->p_reports=p_reps; + this->p_settings=p_sets; this->hive_type=hive_type_string; this->tree_category_items.clear(); this->selected_reports.clear(); + // Restore dialog geometry if possible + QByteArray geometry=this->p_settings->GetWindowGeometry("DlgReportChooser"); + if(!geometry.isEmpty()) this->restoreGeometry(geometry); + // Populate tree with reports tree_cats=this->p_reports->GetAvailableReportCategories(); QListIterator tree_cat_it(tree_cats); while(tree_cat_it.hasNext()) { cur_tree_cat=tree_cat_it.next(); p_tree_cat_widget=new QTreeWidgetItem(this->ui->TrReports); p_tree_cat_widget->setText(0,cur_tree_cat); p_tree_cat_widget->setFlags(Qt::ItemIsEnabled| Qt::ItemIsUserCheckable| Qt::ItemIsTristate); p_tree_cat_widget->setCheckState(0,Qt::Unchecked); tree_cat_reports=this->p_reports->GetAvailableReports(cur_tree_cat); QListIterator tree_cat_rep_it(tree_cat_reports); while(tree_cat_rep_it.hasNext()) { p_report=tree_cat_rep_it.next(); p_tree_cat_rep_widget=new QTreeWidgetItem(p_tree_cat_widget); // Save pointer to ReportTemplate alongside p_tree_cat_rep_widget->setData(0, Qt::UserRole, QVariant().fromValue(p_report)); p_tree_cat_rep_widget->setText(0,p_report->Name()); p_tree_cat_rep_widget->setFlags(Qt::ItemIsEnabled| Qt::ItemIsSelectable| Qt::ItemIsUserCheckable); if(this->hive_type!="UNKNOWN" && this->hive_type==p_report->Hive()) { p_tree_cat_rep_widget->setCheckState(0,Qt::Checked); } else { p_tree_cat_rep_widget->setCheckState(0,Qt::Unchecked); } } this->tree_category_items.append(p_tree_cat_widget); } // Finally, expand all categories this->ui->TrReports->expandAll(); } DlgReportChooser::~DlgReportChooser() { delete this->ui; } QList DlgReportChooser::GetSelectedReports() { return this->selected_reports; } void DlgReportChooser::changeEvent(QEvent *e) { QDialog::changeEvent(e); switch (e->type()) { case QEvent::LanguageChange: this->ui->retranslateUi(this); break; default: break; } } +void DlgReportChooser::closeEvent(QCloseEvent *p_event) { + Q_UNUSED(p_event) + + this->p_settings->SaveWindowGeometry("DlgReportChooser",this->saveGeometry()); +} + void DlgReportChooser::on_BtnCancel_clicked() { this->reject(); } void DlgReportChooser::on_TrReports_currentItemChanged( QTreeWidgetItem *p_current, QTreeWidgetItem *p_previous) { Q_UNUSED(p_previous) // If item has no parent, clear labels and return if(p_current->parent()==NULL) { this->ui->LblAuthor->clear(); this->ui->LblDesc->clear(); return; } // Update labels this->ui->LblAuthor->setText( p_current->data(0,Qt::UserRole).value()->Author()); this->ui->LblDesc->setText( p_current->data(0,Qt::UserRole).value()->Description()); } void DlgReportChooser::on_BtnGenerate_clicked() { QTreeWidgetItem *p_cat; int i; // Add selected reports to selected_reports QListIterator cat_it(this->tree_category_items); while(cat_it.hasNext()) { p_cat=cat_it.next(); for(i=0;ichildCount();i++) { if(p_cat->child(i)->checkState(0)==Qt::Checked) { // Get saved pointer to ReportTemplate and append it to selected_reps this->selected_reports.append(p_cat-> child(i)->data(0,Qt::UserRole).value()); } } } this->accept(); } diff --git a/trunk/dlgreportchooser.h b/trunk/dlgreportchooser.h index a8820b7..2967169 100644 --- a/trunk/dlgreportchooser.h +++ b/trunk/dlgreportchooser.h @@ -1,62 +1,66 @@ /******************************************************************************* * fred Copyright (c) 2011-2013 by Gillen Daniel * * * * Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor * * with special feautures useful during forensic analysis. * * * * This program is free software: you can redistribute it and/or modify it * * under the terms of the GNU General Public License as published by the Free * * Software Foundation, either version 3 of the License, or (at your option) * * any later version. * * * * This program is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * *******************************************************************************/ #ifndef DLGREPORTCHOOSER_H #define DLGREPORTCHOOSER_H #include "reports.h" +#include "settings.h" #include #include #include namespace Ui { class DlgReportChooser; } class DlgReportChooser : public QDialog { Q_OBJECT public: explicit DlgReportChooser(Reports *p_reps, QString hive_type_string, + Settings *p_sets, QWidget *p_parent=0); ~DlgReportChooser(); QList GetSelectedReports(); protected: void changeEvent(QEvent *e); + void closeEvent(QCloseEvent *p_event); private slots: void on_BtnCancel_clicked(); void on_TrReports_currentItemChanged(QTreeWidgetItem *p_current, QTreeWidgetItem *p_previous); void on_BtnGenerate_clicked(); private: Ui::DlgReportChooser *ui; Reports *p_reports; + Settings *p_settings; QString hive_type; QList tree_category_items; QList selected_reports; }; #endif // DLGREPORTCHOOSER_H diff --git a/trunk/dlgreportviewer.cpp b/trunk/dlgreportviewer.cpp index 30d5675..695632a 100644 --- a/trunk/dlgreportviewer.cpp +++ b/trunk/dlgreportviewer.cpp @@ -1,107 +1,117 @@ /******************************************************************************* * fred Copyright (c) 2011-2013 by Gillen Daniel * * * * Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor * * with special feautures useful during forensic analysis. * * * * This program is free software: you can redistribute it and/or modify it * * under the terms of the GNU General Public License as published by the Free * * Software Foundation, either version 3 of the License, or (at your option) * * any later version. * * * * This program is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * *******************************************************************************/ #include "dlgreportviewer.h" #include "ui_dlgreportviewer.h" #include #include #include #include #include -DlgReportViewer::DlgReportViewer(QString &report_data, QWidget *p_parent) +DlgReportViewer::DlgReportViewer(QString &report_data, + Settings *p_sets, + QWidget *p_parent) : QMainWindow(p_parent,Qt::Dialog | Qt::Popup), ui(new Ui::DlgReportViewer) { // Init local vars ui->setupUi(this); this->p_local_event_loop=NULL; this->orig_report_data=report_data; + this->p_settings=p_sets; + + // Try to restore dialog geometry + QByteArray geometry=this->p_settings->GetWindowGeometry("DlgReportViewer"); + if(!geometry.isEmpty()) this->restoreGeometry(geometry); // Set report content this->ui->WebView->setHtml(report_data); // Set dialog title based on report content title QString report_title=this->ui->WebView->title(); this->setWindowTitle("Report Viewer"); } DlgReportViewer::~DlgReportViewer() { delete ui; if(this->p_local_event_loop!=NULL) this->p_local_event_loop->exit(); } void DlgReportViewer::changeEvent(QEvent *e) { QMainWindow::changeEvent(e); switch(e->type()) { case QEvent::LanguageChange: ui->retranslateUi(this); break; default: break; } } void DlgReportViewer::closeEvent(QCloseEvent *event) { + // Save dialog geometry + this->p_settings->SaveWindowGeometry("DlgReportViewer",this->saveGeometry()); + // Make sure we exit the local event loop on exit if(this->p_local_event_loop!=NULL) { this->p_local_event_loop->exit(); this->p_local_event_loop=NULL; } event->accept(); } void DlgReportViewer::exec() { // Create local event loop this->p_local_event_loop=new QEventLoop(this); // Show window and enter loop this->show(); this->p_local_event_loop->exec(); } void DlgReportViewer::on_action_Print_triggered() { // Print report QPrinter printer; QPrintDialog *p_dlg_print=new QPrintDialog(&printer); if(p_dlg_print->exec()==QDialog::Accepted) { this->ui->WebView->print(&printer); } delete p_dlg_print; } void DlgReportViewer::on_action_Close_triggered() { this->close(); } void DlgReportViewer::on_action_Save_triggered() { QString filename=QFileDialog::getSaveFileName(this, tr("Save report as"), "", "ODF file (*.odf)"); if(filename!="") { QTextDocument *p_doc=new QTextDocument(this); p_doc->setHtml(this->orig_report_data); QTextDocumentWriter *p_doc_writer=new QTextDocumentWriter(filename); p_doc_writer->setFormat(QByteArray("ODF")); p_doc_writer->write(p_doc); delete p_doc_writer; delete p_doc; } } diff --git a/trunk/dlgreportviewer.h b/trunk/dlgreportviewer.h index 89fc1d5..04f8f53 100644 --- a/trunk/dlgreportviewer.h +++ b/trunk/dlgreportviewer.h @@ -1,59 +1,62 @@ /******************************************************************************* * fred Copyright (c) 2011-2013 by Gillen Daniel * * * * Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor * * with special feautures useful during forensic analysis. * * * * This program is free software: you can redistribute it and/or modify it * * under the terms of the GNU General Public License as published by the Free * * Software Foundation, either version 3 of the License, or (at your option) * * any later version. * * * * This program is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * *******************************************************************************/ #ifndef DLGREPORTVIEWER_H #define DLGREPORTVIEWER_H +#include "settings.h" + #include #include #include namespace Ui { class DlgReportViewer; } class DlgReportViewer : public QMainWindow { Q_OBJECT public: explicit DlgReportViewer(QString &report_data, + Settings *p_sets, QWidget *p_parent=0); ~DlgReportViewer(); void exec(); protected: void changeEvent(QEvent *e); void closeEvent(QCloseEvent *event); private slots: void on_action_Print_triggered(); void on_action_Close_triggered(); void on_action_Save_triggered(); private: Ui::DlgReportViewer *ui; QEventLoop *p_local_event_loop; QString orig_report_data; - + Settings *p_settings; }; #endif // DLGREPORTVIEWER_H diff --git a/trunk/mainwindow.cpp b/trunk/mainwindow.cpp index 91da1bc..bc5ebd0 100644 --- a/trunk/mainwindow.cpp +++ b/trunk/mainwindow.cpp @@ -1,598 +1,675 @@ /******************************************************************************* * fred Copyright (c) 2011-2013 by Gillen Daniel * * * * Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor * * with special feautures useful during forensic analysis. * * * * This program is free software: you can redistribute it and/or modify it * * under the terms of the GNU General Public License as published by the Free * * Software Foundation, either version 3 of the License, or (at your option) * * any later version. * * * * This program is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * *******************************************************************************/ #ifndef FRED_REPORT_TEMPLATE_DIR #ifndef __MINGW32__ #define FRED_REPORT_TEMPLATE_DIR "/usr/share/fred/report_templates/" #else #define FRED_REPORT_TEMPLATE_DIR ".\\report_templates\\" #endif #endif #include #include #include #include #include #include #include #include #include "mainwindow.h" #include "ui_mainwindow.h" #include "dlgabout.h" #include "dlgkeydetails.h" #include "dlgreportchooser.h" #include "dlgreportviewer.h" #include "dlgsearch.h" #include "compileinfo.h" /******************************************************************************* * Public ******************************************************************************/ MainWindow::MainWindow(ArgParser *p_arg_parser) : QMainWindow(0), ui(new Ui::MainWindow) { ui->setupUi(this); // Initialize private vars this->p_args=p_arg_parser; this->p_hive=new RegistryHive(this); this->is_hive_open=false; this->p_reg_node_tree_model=NULL; this->p_reg_node_tree_model_proxy=NULL; this->p_reg_key_table_model=NULL; this->p_search_thread=NULL; this->search_result_widgets.clear(); // Init settings this->p_settings=new Settings(this); - if(!this->p_settings->Init()) { - // TODO: Warn user - qDebug()<<"Unable to init settings!"; - } - - // Check for ~/.fred config dir - //this->CheckUserConfigDir(); // Set main window size - int cur_screen=QApplication::desktop()->screenNumber(this); - int window_width= - QApplication::desktop()->availableGeometry(cur_screen).width()*0.5; - int window_height= - QApplication::desktop()->availableGeometry(cur_screen).height()*0.5; - int window_x= - (QApplication::desktop()->availableGeometry(cur_screen).width()/2)- - (window_width/2); - int window_y= - (QApplication::desktop()->availableGeometry(cur_screen).height()/2)- - (window_height/2); - this->setGeometry(window_x, - window_y, - window_width, - window_height); + QByteArray geometry=this->p_settings->GetWindowGeometry("MainWindow"); + if(!geometry.isEmpty()) { + // Restore saved geometry + this->restoreGeometry(geometry); + } else { + // No saved geometry, calculate and set default + int cur_screen=QApplication::desktop()->screenNumber(this); + int window_width= + QApplication::desktop()->availableGeometry(cur_screen).width()*0.5; + int window_height= + QApplication::desktop()->availableGeometry(cur_screen).height()*0.5; + int window_x= + (QApplication::desktop()->availableGeometry(cur_screen).width()/2)- + (window_width/2); + int window_y= + (QApplication::desktop()->availableGeometry(cur_screen).height()/2)- + (window_height/2); + this->setGeometry(window_x, + window_y, + window_width, + window_height); + } // Create widgets this->p_horizontal_splitter=new QSplitter(); this->p_horizontal_splitter->setOrientation(Qt::Horizontal); this->p_node_tree=new RegistryNodeTree(this->p_horizontal_splitter); this->p_vertical_splitter=new QSplitter(this->p_horizontal_splitter); this->p_vertical_splitter->setOrientation(Qt::Vertical); this->p_key_table=new RegistryKeyTable(this->p_vertical_splitter); this->p_tab_widget=new TabWidget(this->p_vertical_splitter); this->p_hex_edit_widget=new HexEditWidget(); // Add hexedit page to tab_widget this->p_tab_widget->addTab(this->p_hex_edit_widget,tr("Hex viewer")); // Add widgets to their splitters this->p_vertical_splitter->addWidget(this->p_key_table); this->p_vertical_splitter->addWidget(this->p_tab_widget); this->p_horizontal_splitter->addWidget(this->p_node_tree); this->p_horizontal_splitter->addWidget(this->p_vertical_splitter); // Set stretch factors QSizePolicy node_tree_policy=this->p_node_tree->sizePolicy(); node_tree_policy.setHorizontalStretch(1); node_tree_policy.setVerticalStretch(100); this->p_node_tree->setSizePolicy(node_tree_policy); QSizePolicy vertical_splitter_policy=this->p_vertical_splitter->sizePolicy(); vertical_splitter_policy.setHorizontalStretch(4); vertical_splitter_policy.setVerticalStretch(100); this->p_vertical_splitter->setSizePolicy(vertical_splitter_policy); QSizePolicy key_table_policy=this->p_key_table->sizePolicy(); key_table_policy.setVerticalStretch(5); key_table_policy.setHorizontalStretch(100); this->p_key_table->setSizePolicy(key_table_policy); QSizePolicy tab_widget_policy=this->p_tab_widget->sizePolicy(); tab_widget_policy.setVerticalStretch(2); tab_widget_policy.setHorizontalStretch(200); this->p_tab_widget->setSizePolicy(tab_widget_policy); // Connect signals this->connect(this->p_node_tree, SIGNAL(clicked(QModelIndex)), this, SLOT(SlotNodeTreeClicked(QModelIndex))); this->connect(this->p_node_tree, SIGNAL(activated(QModelIndex)), this, SLOT(SlotNodeTreeClicked(QModelIndex))); this->connect(this->p_node_tree, SIGNAL(CurrentItemChanged(QModelIndex)), this, SLOT(SlotNodeTreeClicked(QModelIndex))); this->connect(this->p_key_table, SIGNAL(clicked(QModelIndex)), this, SLOT(SlotKeyTableClicked(QModelIndex))); this->connect(this->p_key_table, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(SlotKeyTableDoubleClicked(QModelIndex))); this->connect(this->p_key_table, SIGNAL(CurrentItemChanged(QModelIndex)), this, SLOT(SlotKeyTableClicked(QModelIndex))); this->connect(this->p_tab_widget, SIGNAL(tabCloseRequested(int)), this, SLOT(SlotTabCloseButtonClicked(int))); // Add central widget this->setCentralWidget(this->p_horizontal_splitter); this->centralWidget()->setContentsMargins(4,4,4,0); // Set window title this->UpdateWindowTitle(); + // Create and update recently opened menu + this->p_recently_opened_menu=new QMenu(this); + this->ui->ActionRecentlyOpened->setMenu(this->p_recently_opened_menu); + this->UpdateRecentlyOpenedMenu(); + // Set last open location to home dir this->last_open_location=QDir::homePath(); // Load report templates this->p_reports=new Reports(); this->ReloadReportTemplates(); // Finally, react on some command line arguments if(this->p_args->IsSet("maximized")) { this->setWindowState(Qt::WindowMaximized); } if(this->p_args->IsSet("fullscreen")) { this->setWindowState(Qt::WindowFullScreen); } if(this->p_args->IsSet("hive-file")) { this->OpenHive(this->p_args->GetArgVal("hive-file")); } } MainWindow::~MainWindow() { if(this->is_hive_open) { this->p_hive->Close(); } + + // Delete created objects + delete this->p_reports; + this->ClearRecentlyOpenedMenu(); + delete this->p_recently_opened_menu; + delete this->p_hex_edit_widget; + delete this->p_tab_widget; + delete this->p_key_table; + delete this->p_vertical_splitter; + delete this->p_node_tree; + delete this->p_horizontal_splitter; + delete this->p_settings; + delete this->p_hive; delete ui; } +/******************************************************************************* + * Protected + ******************************************************************************/ + +void MainWindow::closeEvent(QCloseEvent *p_event) { + Q_UNUSED(p_event) + + // Save window position and size on exit + this->p_settings->SaveWindowGeometry("MainWindow",this->saveGeometry()); + QMainWindow::closeEvent(p_event); +} + /******************************************************************************* * Private slots ******************************************************************************/ void MainWindow::on_action_Quit_triggered() { qApp->exit(); } void MainWindow::on_action_Open_hive_triggered() { QString hive_file=""; hive_file=QFileDialog::getOpenFileName(this, tr("Open registry hive"), this->last_open_location, tr("All files (*)")); if(hive_file=="") return; this->OpenHive(hive_file); } void MainWindow::on_action_Close_hive_triggered() { if(this->is_hive_open) { // Remove search results while(this->p_tab_widget->count()>1) { this->p_tab_widget->removeTab(this->p_tab_widget->count()-1); delete this->search_result_widgets.at(this->p_tab_widget->count()-1); this->search_result_widgets.removeLast(); } // Delete models if(this->p_reg_node_tree_model!=NULL) { this->p_node_tree->setModel(NULL); delete this->p_reg_node_tree_model_proxy; delete this->p_reg_node_tree_model; this->p_reg_node_tree_model_proxy=NULL; this->p_reg_node_tree_model=NULL; } if(this->p_reg_key_table_model!=NULL) { this->p_key_table->setModel(NULL); delete this->p_reg_key_table_model; this->p_reg_key_table_model=NULL; } // Remove any data from hex edit and data interpreter this->p_hex_edit_widget->SetData(QByteArray()); this->p_hex_edit_widget->setEnabled(false); // Close hive this->p_hive->Close(); this->is_hive_open=false; this->ui->action_Close_hive->setEnabled(false); this->ui->ActionSearch->setEnabled(false); this->ui->MenuReports->setEnabled(false); this->UpdateWindowTitle(); } } void MainWindow::on_actionAbout_Qt_triggered() { QMessageBox::aboutQt(this,tr("About Qt")); } void MainWindow::on_actionAbout_fred_triggered() { DlgAbout dlg_about(this); dlg_about.exec(); } void MainWindow::on_ActionSearch_triggered() { DlgSearch dlg_search(this); if(dlg_search.exec()==QDialog::Accepted) { // Create search thread and connect needed signals/slots this->p_search_thread=new ThreadSearch(this); // Add new search widget to tabwidget and to internal widget list SearchResultWidget *p_search_widget= new SearchResultWidget(this->p_tab_widget); p_search_widget->setEnabled(false); this->search_result_widgets.append(p_search_widget); this->connect(p_search_widget, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(SlotSearchResultWidgetDoubleClicked(QModelIndex))); this->p_tab_widget->addTab(p_search_widget,tr("Search results"),true); this->p_tab_widget->setCurrentIndex(this->p_tab_widget->count()-1); // Connect search thread to result widget this->connect(this->p_search_thread, SIGNAL(SignalFoundMatch(ThreadSearch::eMatchType, QString,QString,QString)), p_search_widget, SLOT(SlotFoundMatch(ThreadSearch::eMatchType, QString,QString,QString))); this->connect(this->p_search_thread, SIGNAL(finished()), this, SLOT(SlotSearchFinished())); this->connect(this->p_search_thread, SIGNAL(finished()), p_search_widget, SLOT(SlotSearchFinished())); // Start searching this->ui->ActionSearch->setEnabled(false); p_search_thread->Search(this->p_hive->Filename(), dlg_search.Keywords(), dlg_search.SearchNodeNames(), dlg_search.SearchKeyNames(), dlg_search.SearchKeyValues()); } } void MainWindow::on_ActionGenerateReport_triggered() { DlgReportChooser dlg_repchooser(this->p_reports, this->p_hive->HiveTypeToString( this->p_hive->HiveType()), + this->p_settings, this); if(dlg_repchooser.exec()==QDialog::Accepted) { QList selected_reports; // Get selected report selected_reports=dlg_repchooser.GetSelectedReports(); if(selected_reports.isEmpty()) return; // Generate report(s) QString report_result=""; if(this->p_reports->GenerateReport(this->p_hive, selected_reports, report_result, false)) { // Report generation was successfull, show reports DlgReportViewer *p_dlg_report_view=new DlgReportViewer(report_result, + this->p_settings, this); p_dlg_report_view->exec(); delete p_dlg_report_view; } else { // TODO: Inform user qDebug()<<"ERROR: "<p_reg_node_tree_model_proxy->mapToSource(index); // Built node path node_path=this->p_reg_node_tree_model->GetNodePath(index); // Create table model and attach it to the table view if(this->p_reg_key_table_model!=NULL) { // If a previous model was set, delete it and clear hexedit etc... this->p_key_table->setModel(NULL); delete this->p_reg_key_table_model; this->p_hex_edit_widget->SetData(QByteArray()); } this->p_reg_key_table_model=new RegistryKeyTableModel(this->p_hive,node_path); this->p_key_table->setModel(this->p_reg_key_table_model); // Set focus back to nodetree to be able to navigate with keyboard this->p_node_tree->setFocus(); } void MainWindow::SlotKeyTableClicked(QModelIndex index) { if(!index.isValid()) return; this->selected_key_value= this->p_reg_key_table_model->data(this->p_reg_key_table_model-> index(index.row(),2), RegistryKeyTableModel:: AdditionalRoles_GetRawData) .toByteArray(); this->p_hex_edit_widget->SetData(this->selected_key_value); // Set focus back to nodetree to be able to navigate with keyboard this->p_key_table->setFocus(); } void MainWindow::SlotKeyTableDoubleClicked(QModelIndex index) { Q_UNUSED(index); /* QModelIndex key_index; QModelIndex node_index; QStringList nodes; QString key_name; QString key_type; QByteArray key_value; if(!index.isValid()) return; // Get key name, type and value key_index=this->p_reg_key_table_model->index(index.row(),0); key_name=this->p_reg_key_table_model->data(key_index,Qt::DisplayRole) .toString(); key_index=this->p_reg_key_table_model->index(index.row(),1); key_type=this->p_reg_key_table_model->data(key_index,Qt::DisplayRole) .toString();ThreadSearch key_index=this->p_reg_key_table_model->index(index.row(),2); key_value=this->p_reg_key_table_model->data(key_index, RegistryKeyTableModel:: AdditionalRoles_GetRawData) .toByteArray(); // Get current node node_index=this->p_node_tree->currentIndex(); //Built node path nodes.clear(); nodes.append(this->p_reg_node_tree_model-> data(node_index,Qt::DisplayRole).toString()); while(this->p_reg_node_tree_model->parent(node_index)!=QModelIndex()) { // Prepend all parent nodes node_index=this->p_reg_node_tree_model->parent(node_index); nodes.prepend(this->p_reg_node_tree_model-> data(node_index,Qt::DisplayRole).toString()); } DlgKeyDetails dlg_key_details(this); dlg_key_details.SetValues(nodes,key_name,key_type,key_value); dlg_key_details.exec(); */ } void MainWindow::SlotSearchFinished() { delete this->p_search_thread; this->p_search_thread=NULL; this->ui->ActionSearch->setEnabled(true); // Enable result widget this->search_result_widgets.last()->setEnabled(true); } void MainWindow::SlotSearchResultWidgetDoubleClicked(QModelIndex index) { SearchResultWidget *p_sender; QString path; QString match_type; QString value; QString key=""; int i; if(!index.isValid()) return; // Get pointer to sender p_sender=(SearchResultWidget*)QObject::sender(); // Get path and matchtype path=p_sender->item(index.row(),0)->text(); match_type=p_sender->item(index.row(),1)->text(); value=p_sender->item(index.row(),2)->text(); if(match_type==tr("Node name")) { // Node name is not part of path. Add it if(path=="\\") path.append(value); else path.append("\\").append(value); } else if(match_type==tr("Key name")) { // Key name is stored in value key=value; } else if(match_type==tr("Key value")) { // Key name is part of path. Save and remove it QStringList nodes=path.split("\\",QString::SkipEmptyParts); key=nodes.at(nodes.count()-1); // Remove \ from path path.chop(key.length()+1); } // Expand treeview to correct node QList indexes= this->p_reg_node_tree_model->GetIndexListOf(path); for(i=0;ip_reg_node_tree_model_proxy-> mapFromSource(indexes.at(i))); this->p_node_tree->expand(indexes.at(i)); } if(indexes.count()>0) { // Scroll to last expanded node, select it and update widgets this->p_node_tree->scrollTo(indexes.at(indexes.count()-1), QAbstractItemView::PositionAtCenter); this->p_node_tree->selectionModel()->clear(); this->p_node_tree->selectionModel()-> select(indexes.at(indexes.count()-1), QItemSelectionModel::Select); // TODO: This does not work!! this->SlotNodeTreeClicked(indexes.at(indexes.count()-1)); } // Select correct key if search matched on keay name / value if(key!="") { int row=this->p_reg_key_table_model->GetKeyRow(key); this->p_key_table->clearSelection(); this->p_key_table->scrollTo(this->p_reg_key_table_model->index(row,0), QAbstractItemView::PositionAtCenter); this->p_key_table->selectRow(row); this->SlotKeyTableClicked(this->p_reg_key_table_model->index(row,0)); } } void MainWindow::SlotTabCloseButtonClicked(int index) { // Delete tab widget and remove tab this->p_tab_widget->removeTab(index); delete this->search_result_widgets.at(index-1); this->search_result_widgets.removeAt(index-1); } +void MainWindow::SlotRecentlyOpenedFileClicked(bool checked) { + Q_UNUSED(checked) + + QAction *p_sender=(QAction*)QObject::sender(); + this->OpenHive(p_sender->text()); +} + /******************************************************************************* * Private ******************************************************************************/ void MainWindow::CheckUserConfigDir() { QString user_config_dir=QDir::homePath() .append(QDir::separator()) .append(".fred"); if(!QDir(user_config_dir).exists()) { // User config dir does not exists, try to create it if(!QDir().mkpath(user_config_dir)) { // TODO: Maybe warn user return; } user_config_dir.append(QDir::separator()).append("report_templates"); if(!QDir().mkpath(user_config_dir)) { // TODO: Maybe warn user return; } } } void MainWindow::UpdateWindowTitle(QString filename) { if(filename=="") { this->setWindowTitle(QString("%1 v%2").arg(APP_TITLE,APP_VERSION)); } else { this->setWindowTitle(QString("%1 v%2 - %3").arg(APP_TITLE, APP_VERSION, filename.toLocal8Bit() .constData())); } } void MainWindow::OpenHive(QString hive_file) { // Update last open location this->last_open_location=hive_file.left(hive_file. lastIndexOf(QDir::separator())); // If another hive is currently open, close it if(this->is_hive_open) this->on_action_Close_hive_triggered(); // Try to open hive if(!this->p_hive->Open(hive_file)) { QMessageBox::critical(this, tr("Error opening hive file"), tr("Unable to open file '%1'").arg(hive_file)); return; } // Create tree model & proxy this->p_reg_node_tree_model=new RegistryNodeTreeModel(this->p_hive); this->p_reg_node_tree_model_proxy=new RegistryNodeTreeModelProxy(this); //this->p_reg_node_tree_model_proxy->setDynamicSortFilter(true); this->p_reg_node_tree_model_proxy-> setSourceModel(this->p_reg_node_tree_model); this->p_node_tree->setModel(this->p_reg_node_tree_model_proxy); this->is_hive_open=true; this->ui->action_Close_hive->setEnabled(true); this->ui->ActionSearch->setEnabled(true); this->ui->MenuReports->setEnabled(true); // Enable data interpreter this->p_hex_edit_widget->setEnabled(true); + // Update window title this->UpdateWindowTitle(hive_file); + + // Add file to recent list and update recently opened menu + this->p_settings->AddRecentFile(hive_file); + this->UpdateRecentlyOpenedMenu(); } void MainWindow::ReloadReportTemplates() { QListIterator it(this->p_settings->GetReportTemplateDirs()); while(it.hasNext()) { this->p_reports->LoadReportTemplates(it.next()); } -/* - // Load reports from system wide include dir - this->p_reports->LoadReportTemplates(FRED_REPORT_TEMPLATE_DIR); - // Load user's report templates - this->p_reports->LoadReportTemplates(QDir::homePath() - .append(QDir::separator()) - .append(".fred") - .append(QDir::separator()) - .append("report_templates")); -*/ } void MainWindow::on_ActionReloadReportTemplates_triggered() { this->ReloadReportTemplates(); } + +void MainWindow::ClearRecentlyOpenedMenu() { + QAction *p_action; + + // Remove existing menu entries + QList menu_entries=this->p_recently_opened_menu->actions(); + QListIterator it_me(menu_entries); + while(it_me.hasNext()) { + p_action=it_me.next(); + this->p_recently_opened_menu->removeAction(p_action); + delete p_action; + } +} + +void MainWindow::UpdateRecentlyOpenedMenu() { + QStringList recent_files=this->p_settings->GetRecentFiles(); + QAction *p_action; + + // Remove existing menu entries + this->ClearRecentlyOpenedMenu(); + + // If there are no recent files, disable submenu and return + if(recent_files.isEmpty()) { + this->ui->ActionRecentlyOpened->setEnabled(false); + return; + } else { + this->ui->ActionRecentlyOpened->setEnabled(true); + } + + // Add recently opened files to menu + QListIterator it_rf(recent_files); + while(it_rf.hasNext()) { + // Create menu entry + p_action=new QAction(it_rf.next(),this->p_recently_opened_menu); + // Connect it to us + this->connect(p_action, + SIGNAL(triggered(bool)), + this, + SLOT(SlotRecentlyOpenedFileClicked(bool))); + // Add it to submenu + this->p_recently_opened_menu->addAction(p_action); + } +} diff --git a/trunk/mainwindow.h b/trunk/mainwindow.h index 12d3374..c29beb3 100644 --- a/trunk/mainwindow.h +++ b/trunk/mainwindow.h @@ -1,127 +1,119 @@ /******************************************************************************* * fred Copyright (c) 2011-2013 by Gillen Daniel * * * * Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor * * with special feautures useful during forensic analysis. * * * * This program is free software: you can redistribute it and/or modify it * * under the terms of the GNU General Public License as published by the Free * * Software Foundation, either version 3 of the License, or (at your option) * * any later version. * * * * This program is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * *******************************************************************************/ #ifndef MAINWINDOW_H #define MAINWINDOW_H #include #include #include #include #include #include #include #include #include #include "argparser.h" #include "registryhive.h" #include "registrynodetree.h" #include "registrynodetreemodel.h" #include "registrynodetreemodelproxy.h" #include "registrykeytable.h" #include "registrykeytablemodel.h" #include "hexeditwidget.h" #include "reports.h" #include "threadsearch.h" #include "searchresultwidget.h" #include "tabwidget.h" #include "settings.h" namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(ArgParser *p_arg_parser); ~MainWindow(); + protected: + void closeEvent(QCloseEvent *p_event); + private slots: void on_action_Quit_triggered(); void on_action_Open_hive_triggered(); void on_action_Close_hive_triggered(); void on_actionAbout_Qt_triggered(); void on_actionAbout_fred_triggered(); void on_ActionSearch_triggered(); void on_ActionGenerateReport_triggered(); + void on_ActionReloadReportTemplates_triggered(); void SlotNodeTreeClicked(QModelIndex index); void SlotKeyTableClicked(QModelIndex index); void SlotKeyTableDoubleClicked(QModelIndex index); void SlotSearchFinished(); void SlotSearchResultWidgetDoubleClicked(QModelIndex index); void SlotTabCloseButtonClicked(int index); - - void on_ActionReloadReportTemplates_triggered(); + void SlotRecentlyOpenedFileClicked(bool checked); private: Ui::MainWindow *ui; ArgParser *p_args; QString last_open_location; RegistryHive *p_hive; bool is_hive_open; QByteArray selected_key_value; QList search_result_widgets; Settings *p_settings; // Models RegistryNodeTreeModel *p_reg_node_tree_model; RegistryNodeTreeModelProxy *p_reg_node_tree_model_proxy; RegistryKeyTableModel *p_reg_key_table_model; // Widgets etc... RegistryNodeTree *p_node_tree; RegistryKeyTable *p_key_table; TabWidget *p_tab_widget; HexEditWidget *p_hex_edit_widget; QSplitter *p_horizontal_splitter; QSplitter *p_vertical_splitter; Reports *p_reports; + QMenu *p_recently_opened_menu; // Threads ThreadSearch *p_search_thread; - /* - * CheckUserConfigDir - * - * Checks for and possibly creates the ~/.fred directory - */ + // Functions void CheckUserConfigDir(); - /* - * UpdateWindowTitle - * - * Updates the window title - */ void UpdateWindowTitle(QString filename=""); - /* - * OpenHive - * - * Open a registry hive - */ void OpenHive(QString hive_file); void ReloadReportTemplates(); + void ClearRecentlyOpenedMenu(); + void UpdateRecentlyOpenedMenu(); }; #endif // MAINWINDOW_H diff --git a/trunk/mainwindow.ui b/trunk/mainwindow.ui index 88d50fd..bf0c628 100644 --- a/trunk/mainwindow.ui +++ b/trunk/mainwindow.ui @@ -1,154 +1,163 @@ MainWindow 0 0 508 317 0 0 0 0 MainWindow :/icons/resources/fred.png:/icons/resources/fred.png 0 0 508 29 &File + &Help false &Reports &Edit &Open hive Ctrl+O false Close hive &Quit Ctrl+Q About Qt About fred false &Search Ctrl+S false &Preferences true Generate report Reload report templates + + + false + + + Recently opened + + diff --git a/trunk/settings.cpp b/trunk/settings.cpp index 6c26dc6..d6ce478 100644 --- a/trunk/settings.cpp +++ b/trunk/settings.cpp @@ -1,97 +1,122 @@ /******************************************************************************* * fred Copyright (c) 2011-2013 by Gillen Daniel * * * * Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor * * with special feautures useful during forensic analysis. * * * * This program is free software: you can redistribute it and/or modify it * * under the terms of the GNU General Public License as published by the Free * * Software Foundation, either version 3 of the License, or (at your option) * * any later version. * * * * This program is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * *******************************************************************************/ #include "settings.h" #include #ifndef FRED_REPORT_TEMPLATE_DIR #ifndef __MINGW32__ #define SYSTEM_REPORT_TEMPLATE_DIR "/usr/share/fred/report_templates/" #else #define SYSTEM_REPORT_TEMPLATE_DIR ".\\report_templates\\" #endif #endif #define APP_ORGANIZATION "pinguin.lu" #define APP_NAME "fred" Settings::Settings(QObject *p_parent) : QObject(p_parent) { // Init vars this->p_settings=NULL; + this->initialized=false; this->user_settings_dir=QDir::homePath() .append(QDir::separator()).append(".fred"); this->user_report_template_dir=QString(this->user_settings_dir) .append(QDir::separator()) .append("report_templates"); -} -bool Settings::Init() { // Make sure config dirs exist if(!QDir(this->user_settings_dir).exists()) { // User config dir does not exists, try to create it if(!QDir().mkpath(this->user_settings_dir)) { // TODO: Maybe warn user - return false; + return; } } if(!QDir(this->user_report_template_dir).exists()) { // Create config dir sub folder for report templates if(!QDir().mkpath(this->user_report_template_dir)) { // TODO: Maybe warn user - return false; + return; } } // Create / open settings #ifndef __MINGW32__ // On any Unix-like OS, settings should be saved in the .fred folder this->p_settings=new QSettings(QString(this->user_settings_dir) .append(QDir::separator()) .append("fred.conf"), QSettings::NativeFormat, this); -/* - QSettings::setPath(QSettings::NativeFormat, - QSettings::UserScope, - this->user_settings_dir); -*/ #else // On Windows, it can be stored inside registry this->p_settings=new QSettings(QSettings::NativeFormat, QSettings::UserScope, APP_ORGANIZATION, APP_NAME, this); #endif if(this->p_settings->status()!=QSettings::NoError || !this->p_settings->isWritable()) { - return false; + return; } - return true; + this->initialized=true; } QStringList Settings::GetReportTemplateDirs() { return QStringList()<user_report_template_dir; } +void Settings::SaveWindowGeometry(QString window_name, QByteArray geometry) { + if(!this->initialized) return; + this->p_settings->setValue(QString("WindowGeometry_%1").arg(window_name), + geometry); +} + +QByteArray Settings::GetWindowGeometry(QString window_name) { + if(!this->initialized) return QByteArray(); + return this->p_settings->value(QString("WindowGeometry_%1") + .arg(window_name)).toByteArray(); +} + +void Settings::AddRecentFile(QString file) { + // Get recent files + QStringList recent_files=this->GetRecentFiles(); + + if(recent_files.contains(file)) { + // File already exists in recent list. Simply move it to top + recent_files.move(recent_files.indexOf(file),0); + } else { + // We only save 5 files at max + if(recent_files.count()==5) recent_files.removeLast(); + recent_files.prepend(file); + } + + this->p_settings->setValue("RecentFiles",recent_files); +} + +QStringList Settings::GetRecentFiles() { + return this->p_settings->value("RecentFiles").toStringList(); +} diff --git a/trunk/settings.h b/trunk/settings.h index c9db10c..d182721 100644 --- a/trunk/settings.h +++ b/trunk/settings.h @@ -1,44 +1,50 @@ /******************************************************************************* * fred Copyright (c) 2011-2013 by Gillen Daniel * * * * Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor * * with special feautures useful during forensic analysis. * * * * This program is free software: you can redistribute it and/or modify it * * under the terms of the GNU General Public License as published by the Free * * Software Foundation, either version 3 of the License, or (at your option) * * any later version. * * * * This program is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * *******************************************************************************/ #ifndef SETTINGS_H #define SETTINGS_H #include #include #include #include +#include class Settings : public QObject { Q_OBJECT public: explicit Settings(QObject *p_parent=0); - bool Init(); + QStringList GetReportTemplateDirs(); + void SaveWindowGeometry(QString window_name, QByteArray geometry); + QByteArray GetWindowGeometry(QString window_name); + void AddRecentFile(QString file); + QStringList GetRecentFiles(); + private: QSettings *p_settings; + bool initialized; QString user_settings_dir; QString user_report_template_dir; - }; #endif // SETTINGS_H