cutter/src/MainWindow.cpp

735 lines
21 KiB
C++
Raw Normal View History

2017-10-01 19:09:42 +00:00
#include "MainWindow.h"
#include "ui_MainWindow.h"
#include "dialogs/CommentsDialog.h"
#include "dialogs/AboutDialog.h"
#include "dialogs/RenameDialog.h"
#include "dialogs/preferences/PreferencesDialog.h"
2017-10-01 19:09:42 +00:00
#include "utils/Helpers.h"
2018-01-09 12:09:25 +00:00
#include <QApplication>
#include <QComboBox>
#include <QCompleter>
#include <QDebug>
#include <QDesktopServices>
#include <QDir>
#include <QDockWidget>
#include <QFile>
#include <QFileDialog>
#include <QFont>
#include <QFontDialog>
#include <QLabel>
#include <QLineEdit>
#include <QList>
#include <QMessageBox>
#include <QProcess>
#include <QPropertyAnimation>
#include <QScrollBar>
#include <QSettings>
#include <QShortcut>
#include <QStringListModel>
#include <QStyledItemDelegate>
#include <QStyleFactory>
#include <QTextCursor>
#include <QtGlobal>
#include <QToolButton>
#include <QToolTip>
#include <QTreeWidgetItem>
2017-12-23 16:42:42 +00:00
#include <QSvgRenderer>
2017-10-01 19:09:42 +00:00
#include "utils/Highlighter.h"
#include "utils/HexAsciiHighlighter.h"
#include "utils/Helpers.h"
2017-12-23 16:42:42 +00:00
#include "utils/SvgIconEngine.h"
2017-12-23 16:42:42 +00:00
#include "dialogs/NewFileDialog.h"
#include "widgets/DisassemblerGraphView.h"
#include "widgets/GraphWidget.h"
#include "widgets/FunctionsWidget.h"
#include "widgets/SectionsWidget.h"
#include "widgets/CommentsWidget.h"
#include "widgets/ImportsWidget.h"
#include "widgets/ExportsWidget.h"
2018-03-06 17:21:48 +00:00
#include "widgets/TypesWidget.h"
#include "widgets/SearchWidget.h"
#include "widgets/SymbolsWidget.h"
#include "widgets/StringsWidget.h"
#include "widgets/SectionsDock.h"
#include "widgets/RelocsWidget.h"
#include "widgets/FlagsWidget.h"
#include "widgets/VisualNavbar.h"
#include "widgets/Dashboard.h"
#include "widgets/Sidebar.h"
#include "widgets/SdbDock.h"
#include "widgets/Omnibar.h"
#include "widgets/ConsoleWidget.h"
2017-10-01 19:09:42 +00:00
#include "dialogs/OptionsDialog.h"
#include "widgets/EntrypointWidget.h"
#include "dialogs/SaveProjectDialog.h"
2017-12-23 16:42:42 +00:00
#include "widgets/ClassesWidget.h"
2018-02-04 14:32:18 +00:00
#include "widgets/ResourcesWidget.h"
2018-02-26 22:26:18 +00:00
#include "widgets/VTablesWidget.h"
2017-12-13 17:36:00 +00:00
#include "widgets/JupyterWidget.h"
// graphics
#include <QGraphicsEllipseItem>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <cassert>
static void registerCustomFonts()
{
int ret = QFontDatabase::addApplicationFont(":/fonts/Anonymous Pro.ttf");
assert(-1 != ret && "unable to register Anonymous Pro.ttf");
ret = QFontDatabase::addApplicationFont(":/fonts/Inconsolata-Regular.ttf");
assert(-1 != ret && "unable to register Inconsolata-Regular.ttf");
// Do not issue a warning in release
Q_UNUSED(ret)
}
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
core(Core()),
2018-02-04 14:32:18 +00:00
ui(new Ui::MainWindow)
{
panelLock = false;
tabsOnTop = false;
configuration = Config();
}
MainWindow::~MainWindow()
{
}
void MainWindow::initUI()
{
ui->setupUi(this);
registerCustomFonts();
/*
* Toolbar
*/
// Hide central tab widget tabs
QTabBar *centralbar = ui->centralTabWidget->tabBar();
centralbar->setVisible(false);
// Sepparator between undo/redo and goto lineEdit
2017-04-09 19:55:06 +00:00
QWidget *spacer3 = new QWidget();
spacer3->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
spacer3->setMinimumSize(20, 20);
spacer3->setMaximumWidth(300);
2017-11-18 14:57:00 +00:00
ui->mainToolBar->addWidget(spacer3);
// Omnibar LineEdit
this->omnibar = new Omnibar(this);
2017-11-18 14:57:00 +00:00
ui->mainToolBar->addWidget(this->omnibar);
// Add special separators to the toolbar that expand to separate groups of elements
2017-04-09 19:55:06 +00:00
QWidget *spacer2 = new QWidget();
spacer2->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
spacer2->setMinimumSize(10, 10);
spacer2->setMaximumWidth(300);
2017-11-18 14:57:00 +00:00
ui->mainToolBar->addWidget(spacer2);
// Separator between back/forward and undo/redo buttons
2017-04-09 19:55:06 +00:00
QWidget *spacer = new QWidget();
spacer->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
spacer->setMinimumSize(20, 20);
ui->mainToolBar->addWidget(spacer);
// Visual navigation tool bar
this->visualNavbar = new VisualNavbar(this);
this->visualNavbar->setMovable(false);
addToolBarBreak(Qt::TopToolBarArea);
addToolBar(visualNavbar);
/*
* Dock Widgets
*/
2018-02-04 14:32:18 +00:00
dockWidgets.reserve(20);
disassemblyDock = new DisassemblyWidget(this, ui->actionDisassembly);
sidebarDock = new SidebarWidget(this, ui->actionSidebar);
hexdumpDock = new HexdumpWidget(this, ui->actionHexdump);
pseudocodeDock = new PseudocodeWidget(this, ui->actionPseudocode);
consoleDock = new ConsoleWidget(this, ui->actionConsole);
// Add graph view as dockable
graphDock = new GraphWidget(this, ui->actionGraph);
// Hide centralWidget as we do not need it
ui->centralWidget->hide();
sectionsDock = new SectionsDock(this, ui->actionSections);
entrypointDock = new EntrypointWidget(this, ui->actionEntrypoints);
functionsDock = new FunctionsWidget(this, ui->actionFunctions);
importsDock = new ImportsWidget(this, ui->actionImports);
exportsDock = new ExportsWidget(this, ui->actionExports);
typesDock = new TypesWidget(this, ui->actionTypes);
searchDock = new SearchWidget(this, ui->actionSearch);
symbolsDock = new SymbolsWidget(this, ui->actionSymbols);
relocsDock = new RelocsWidget(this, ui->actionRelocs);
commentsDock = new CommentsWidget(this, ui->actionComments);
stringsDock = new StringsWidget(this, ui->actionStrings);
flagsDock = new FlagsWidget(this, ui->actionFlags);
2018-03-02 13:15:53 +00:00
#ifdef CUTTER_ENABLE_JUPYTER
jupyterDock = new JupyterWidget(this, ui->actionJupyter);
#else
ui->actionJupyter->setEnabled(false);
ui->actionJupyter->setVisible(false);
2018-03-02 13:15:53 +00:00
#endif
dashboardDock = new Dashboard(this, ui->actionDashboard);
sdbDock = new SdbDock(this, ui->actionSDBBrowser);
classesDock = new ClassesWidget(this, ui->actionClasses);
resourcesDock = new ResourcesWidget(this, ui->actionResources);
vTablesDock = new VTablesWidget(this, ui->actionVTables);
2017-12-23 16:42:42 +00:00
2018-03-11 11:41:19 +00:00
// Set up dock widgets default layout
resetToDefaultLayout();
// Restore saved settings
this->readSettings();
// TODO: Allow the user to select this option visually in the GUI settings
// Adjust the DockWidget areas
2017-04-09 19:55:06 +00:00
setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea);
//setCorner( Qt::TopRightCorner, Qt::RightDockWidgetArea );
2017-04-09 19:55:06 +00:00
setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea);
//setCorner( Qt::BottomRightCorner, Qt::RightDockWidgetArea );
/*
* Some global shortcuts
*/
// Period goes to command entry
2017-04-09 19:55:06 +00:00
QShortcut *cmd_shortcut = new QShortcut(QKeySequence(Qt::Key_Period), this);
connect(cmd_shortcut, SIGNAL(activated()), consoleDock, SLOT(focusInputLineEdit()));
// G and S goes to goto entry
2017-04-09 19:55:06 +00:00
QShortcut *goto_shortcut = new QShortcut(QKeySequence(Qt::Key_G), this);
connect(goto_shortcut, SIGNAL(activated()), this->omnibar, SLOT(setFocus()));
2017-04-09 19:55:06 +00:00
QShortcut *seek_shortcut = new QShortcut(QKeySequence(Qt::Key_S), this);
connect(seek_shortcut, SIGNAL(activated()), this->omnibar, SLOT(setFocus()));
QShortcut *refresh_shortcut = new QShortcut(QKeySequence(QKeySequence::Refresh), this);
connect(refresh_shortcut, SIGNAL(activated()), this, SLOT(refreshAll()));
connect(core, SIGNAL(projectSaved(const QString &)), this, SLOT(projectSaved(const QString &)));
}
void MainWindow::openNewFile(const QString &fn, int analLevel, QList<QString> advancedOptions)
{
setFilename(fn);
2017-12-14 12:45:03 +00:00
/* Prompt to load filename.r2 script */
QString script = QString("%1.r2").arg(this->filename);
if (r_file_exists(script.toStdString().data())) {
QMessageBox mb;
mb.setWindowTitle(tr("Script loading"));
mb.setText(tr("Do you want to load the '%1' script?").arg(script));
mb.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
if (mb.exec() == QMessageBox::Yes) {
core->loadScript(script);
}
}
/* Show analysis options dialog */
displayAnalysisOptionsDialog(analLevel, advancedOptions);
}
void MainWindow::displayNewFileDialog()
{
NewFileDialog *n = new NewFileDialog();
newFileDialog = n;
n->setAttribute(Qt::WA_DeleteOnClose);
n->show();
}
void MainWindow::closeNewFileDialog()
{
if (newFileDialog) {
newFileDialog->close();
}
newFileDialog = nullptr;
}
void MainWindow::displayAnalysisOptionsDialog(int analLevel, QList<QString> advancedOptions)
{
OptionsDialog *o = new OptionsDialog(this);
o->setAttribute(Qt::WA_DeleteOnClose);
o->show();
2018-03-21 20:32:32 +00:00
if (analLevel >= 0) {
o->setupAndStartAnalysis(analLevel, advancedOptions);
2017-12-06 12:32:35 +00:00
}
}
void MainWindow::openProject(const QString &project_name)
{
QString filename = core->cmd("Pi " + project_name);
setFilename(filename.trimmed());
core->openProject(project_name);
initUI();
finalizeOpen();
}
void MainWindow::finalizeOpen()
{
core->getOpcodes();
// Set settings to override any incorrect saved in the project
core->setSettings();
addOutput(tr(" > Populating UI"));
// FIXME: initialization order frakup. the next line is needed so that the
// comments widget displays the function names.
core->cmd("fs sections");
refreshAll();
addOutput(tr(" > Finished, happy reversing :)"));
// Add fortune message
addOutput("\n" + core->cmd("fo"));
//previewDock->setWindowTitle("entry0");
showMaximized();
}
bool MainWindow::saveProject(bool quit)
{
QString projectName = core->getConfig("prj.name");
2018-03-21 20:32:32 +00:00
if (projectName.isEmpty()) {
return saveProjectAs(quit);
2018-03-21 20:32:32 +00:00
} else {
core->saveProject(projectName);
return true;
}
}
bool MainWindow::saveProjectAs(bool quit)
{
SaveProjectDialog dialog(quit, this);
int result = dialog.exec();
return !quit || result != SaveProjectDialog::Rejected;
}
void MainWindow::refreshOmniBar(const QStringList &flags)
{
omnibar->refresh(flags);
}
void MainWindow::setFilename(const QString &fn)
{
// Add file name to window title
this->filename = fn;
2017-09-25 12:55:41 +00:00
this->setWindowTitle(APPNAME" - " + fn);
}
void MainWindow::closeEvent(QCloseEvent *event)
{
2017-09-25 12:55:41 +00:00
QMessageBox::StandardButton ret = QMessageBox::question(this, APPNAME,
2018-03-21 20:32:32 +00:00
tr("Do you really want to exit?\nSave your project before closing!"),
(QMessageBox::StandardButtons)(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel));
if (ret == QMessageBox::Save) {
if (saveProject(true)) {
saveSettings();
}
QMainWindow::closeEvent(event);
2018-03-21 20:32:32 +00:00
} else if (ret == QMessageBox::Discard) {
saveSettings();
QMainWindow::closeEvent(event);
2018-03-21 20:32:32 +00:00
} else {
event->ignore();
}
}
void MainWindow::readSettings()
{
QSettings settings;
QByteArray geo = settings.value("geometry", QByteArray()).toByteArray();
restoreGeometry(geo);
QByteArray state = settings.value("state", QByteArray()).toByteArray();
restoreState(state);
this->responsive = settings.value("responsive").toBool();
panelLock = settings.value("panelLock").toBool();
setPanelLock();
tabsOnTop = settings.value("tabsOnTop").toBool();
setTabLocation();
updateDockActionsChecked();
}
void MainWindow::saveSettings()
{
QSettings settings;
settings.setValue("geometry", saveGeometry());
settings.setValue("size", size());
settings.setValue("pos", pos());
settings.setValue("state", saveState());
settings.setValue("panelLock", panelLock);
settings.setValue("tabsOnTop", tabsOnTop);
}
void MainWindow::setPanelLock()
{
2018-03-21 20:32:32 +00:00
if (panelLock) {
foreach (QDockWidget *dockWidget, findChildren<QDockWidget *>()) {
dockWidget->setFeatures(QDockWidget::NoDockWidgetFeatures);
}
ui->actionLock->setChecked(false);
2018-03-21 20:32:32 +00:00
} else {
foreach (QDockWidget *dockWidget, findChildren<QDockWidget *>()) {
dockWidget->setFeatures(QDockWidget::AllDockWidgetFeatures);
}
ui->actionLock->setChecked(true);
}
}
void MainWindow::setTabLocation()
{
2018-03-21 20:32:32 +00:00
if (tabsOnTop) {
ui->centralTabWidget->setTabPosition(QTabWidget::North);
this->setTabPosition(Qt::AllDockWidgetAreas, QTabWidget::North);
ui->actionTabs_on_Top->setChecked(true);
2018-03-21 20:32:32 +00:00
} else {
ui->centralTabWidget->setTabPosition(QTabWidget::South);
this->setTabPosition(Qt::AllDockWidgetAreas, QTabWidget::South);
ui->actionTabs_on_Top->setChecked(false);
}
}
void MainWindow::refreshAll()
2017-04-09 19:55:06 +00:00
{
Core()->triggerRefreshAll();
}
void MainWindow::lockUnlock_Docks(bool what)
{
2018-03-21 20:32:32 +00:00
if (what) {
foreach (QDockWidget *dockWidget, findChildren<QDockWidget *>()) {
dockWidget->setFeatures(QDockWidget::NoDockWidgetFeatures);
}
2018-03-21 20:32:32 +00:00
} else {
foreach (QDockWidget *dockWidget, findChildren<QDockWidget *>()) {
dockWidget->setFeatures(QDockWidget::AllDockWidgetFeatures);
}
}
}
void MainWindow::restoreDocks()
{
// In the upper half the functions are the first widget
addDockWidget(Qt::TopDockWidgetArea, functionsDock);
2017-10-13 13:53:23 +00:00
// Function | Dashboard | Sidebar
splitDockWidget(functionsDock, dashboardDock, Qt::Horizontal);
splitDockWidget(dashboardDock, sidebarDock, Qt::Horizontal);
// In the lower half the console is the first widget
addDockWidget(Qt::BottomDockWidgetArea, consoleDock);
// Console | Sections
splitDockWidget(consoleDock, sectionsDock, Qt::Horizontal);
2018-01-09 12:09:25 +00:00
// Tabs for center (must be applied after splitDockWidget())
tabifyDockWidget(sectionsDock, commentsDock);
tabifyDockWidget(dashboardDock, disassemblyDock);
tabifyDockWidget(dashboardDock, graphDock);
tabifyDockWidget(dashboardDock, hexdumpDock);
tabifyDockWidget(dashboardDock, pseudocodeDock);
tabifyDockWidget(dashboardDock, entrypointDock);
tabifyDockWidget(dashboardDock, flagsDock);
tabifyDockWidget(dashboardDock, stringsDock);
tabifyDockWidget(dashboardDock, relocsDock);
tabifyDockWidget(dashboardDock, importsDock);
tabifyDockWidget(dashboardDock, exportsDock);
tabifyDockWidget(dashboardDock, typesDock);
tabifyDockWidget(dashboardDock, searchDock);
tabifyDockWidget(dashboardDock, symbolsDock);
2017-12-23 16:42:42 +00:00
tabifyDockWidget(dashboardDock, classesDock);
2018-02-04 14:32:18 +00:00
tabifyDockWidget(dashboardDock, resourcesDock);
2018-02-26 22:26:18 +00:00
tabifyDockWidget(dashboardDock, vTablesDock);
2018-03-02 13:15:53 +00:00
#ifdef CUTTER_ENABLE_JUPYTER
2017-12-13 17:36:00 +00:00
tabifyDockWidget(dashboardDock, jupyterDock);
2018-03-02 13:15:53 +00:00
#endif
updateDockActionsChecked();
}
void MainWindow::hideAllDocks()
{
2018-03-21 20:32:32 +00:00
for (auto w : dockWidgets) {
2018-01-09 12:09:25 +00:00
removeDockWidget(w);
}
updateDockActionsChecked();
}
void MainWindow::updateDockActionsChecked()
{
2018-03-21 20:32:32 +00:00
for (auto i = dockWidgetActions.constBegin(); i != dockWidgetActions.constEnd(); i++) {
i.key()->setChecked(!i.value()->isHidden());
}
}
void MainWindow::showDefaultDocks()
{
const QList<QDockWidget *> defaultDocks = { sectionsDock,
entrypointDock,
functionsDock,
commentsDock,
stringsDock,
consoleDock,
importsDock,
symbolsDock,
graphDock,
disassemblyDock,
sidebarDock,
hexdumpDock,
pseudocodeDock,
2017-12-13 17:36:00 +00:00
dashboardDock,
2018-03-02 13:15:53 +00:00
#ifdef CUTTER_ENABLE_JUPYTER
2017-12-13 17:36:00 +00:00
jupyterDock
2018-03-02 13:15:53 +00:00
#endif
};
2018-03-21 20:32:32 +00:00
for (auto w : dockWidgets) {
if (defaultDocks.contains(w)) {
w->show();
}
}
updateDockActionsChecked();
}
void MainWindow::resetToDefaultLayout()
{
hideAllDocks();
2018-01-09 12:09:25 +00:00
restoreDocks();
showDefaultDocks();
dashboardDock->raise();
// ugly workaround to set the default widths of functions and sidebar docks
// if anyone finds a way to do this cleaner that also works, feel free to change it!
auto restoreFunctionDock = qhelpers::forceWidth(functionsDock->widget(), 300);
auto restoreSidebarDock = qhelpers::forceWidth(sidebarDock->widget(), 300);
qApp->processEvents();
restoreFunctionDock.restoreWidth(functionsDock->widget());
restoreSidebarDock.restoreWidth(sidebarDock->widget());
Core()->setMemoryWidgetPriority(CutterCore::MemoryWidgetType::Disassembly);
}
2018-01-16 14:09:51 +00:00
void MainWindow::addOutput(const QString &msg)
{
2018-01-16 14:09:51 +00:00
consoleDock->addOutput(msg);
}
void MainWindow::addDebugOutput(const QString &msg)
{
printf("debug output: %s\n", msg.toLocal8Bit().constData());
consoleDock->addDebugOutput(msg);
}
void MainWindow::on_actionLock_triggered()
{
panelLock = !panelLock;
setPanelLock();
}
void MainWindow::on_actionLockUnlock_triggered()
{
2018-03-21 20:32:32 +00:00
if (ui->actionLockUnlock->isChecked()) {
foreach (QDockWidget *dockWidget, findChildren<QDockWidget *>()) {
2018-01-16 14:09:51 +00:00
dockWidget->setFeatures(QDockWidget::NoDockWidgetFeatures);
}
ui->actionLockUnlock->setIcon(QIcon(":/lock"));
2018-03-21 20:32:32 +00:00
} else {
foreach (QDockWidget *dockWidget, findChildren<QDockWidget *>()) {
2018-01-16 14:09:51 +00:00
dockWidget->setFeatures(QDockWidget::AllDockWidgetFeatures);
}
ui->actionLockUnlock->setIcon(QIcon(":/unlock"));
}
}
void MainWindow::on_actionFunctionsRename_triggered()
{
2017-04-09 19:55:06 +00:00
RenameDialog *r = new RenameDialog(this);
// Get function based on click position
//r->setFunctionName(fcn_name);
r->open();
}
2018-01-16 14:09:51 +00:00
void MainWindow::on_actionDefault_triggered()
{
2018-01-16 14:09:51 +00:00
resetToDefaultLayout();
}
void MainWindow::on_actionNew_triggered()
{
2018-01-16 14:09:51 +00:00
on_actionOpen_triggered();
}
void MainWindow::on_actionSave_triggered()
{
saveProject();
}
void MainWindow::on_actionSaveAs_triggered()
{
saveProjectAs();
}
void MainWindow::on_actionRun_Script_triggered()
{
QFileDialog dialog(this);
dialog.setFileMode(QFileDialog::ExistingFile);
dialog.setViewMode(QFileDialog::Detail);
dialog.setDirectory(QDir::home());
QString fileName;
fileName = dialog.getOpenFileName(this, tr("Select radare2 script"));
2017-04-13 15:51:58 +00:00
if (!fileName.length()) //cancel was pressed
2017-04-09 20:36:17 +00:00
return;
this->core->cmd(". " + fileName);
}
2018-01-16 14:09:51 +00:00
void MainWindow::on_actionOpen_triggered()
{
QProcess process(this);
process.setEnvironment(QProcess::systemEnvironment());
process.startDetached(qApp->applicationFilePath());
}
2017-04-09 19:55:06 +00:00
void MainWindow::toggleResponsive(bool maybe)
{
this->responsive = maybe;
// Save options in settings
QSettings settings;
settings.setValue("responsive", this->responsive);
}
void MainWindow::on_actionTabs_on_Top_triggered()
{
this->on_actionTabs_triggered();
}
void MainWindow::on_actionReset_settings_triggered()
{
QMessageBox::StandardButton ret =
2017-09-25 12:55:41 +00:00
(QMessageBox::StandardButton)QMessageBox::question(this, APPNAME,
2018-03-21 20:32:32 +00:00
tr("Do you really want to clear all settings?"),
QMessageBox::Ok | QMessageBox::Cancel);
if (ret == QMessageBox::Ok) {
2017-12-03 12:10:09 +00:00
Config()->resetAll();
}
}
void MainWindow::on_actionQuit_triggered()
{
close();
}
2018-03-08 09:11:19 +00:00
void MainWindow::on_actionBackward_triggered()
{
Core()->seekPrev();
}
2018-01-16 14:09:51 +00:00
void MainWindow::on_actionForward_triggered()
{
2018-03-08 09:11:19 +00:00
Core()->seekNext();
}
void MainWindow::on_actionUndoSeek_triggered()
{
Core()->seekPrev();
}
void MainWindow::on_actionRedoSeek_triggered()
{
Core()->seekNext();
2018-01-16 14:09:51 +00:00
}
void MainWindow::on_actionDisasAdd_comment_triggered()
{
CommentsDialog *c = new CommentsDialog(this);
c->exec();
delete c;
}
void MainWindow::on_actionRefresh_contents_triggered()
{
refreshAll();
}
2017-08-31 17:43:46 +00:00
void MainWindow::on_actionPreferences_triggered()
2017-08-31 17:43:46 +00:00
{
auto dialog = new PreferencesDialog(this);
dialog->show();
2017-09-02 08:17:48 +00:00
}
2018-01-16 14:09:51 +00:00
void MainWindow::on_actionTabs_triggered()
{
tabsOnTop = !tabsOnTop;
setTabLocation();
}
void MainWindow::on_actionAbout_triggered()
{
AboutDialog *a = new AboutDialog(this);
a->open();
}
void MainWindow::on_actionRefresh_Panels_triggered()
{
this->refreshAll();
}
void MainWindow::on_actionAnalyze_triggered()
{
displayAnalysisOptionsDialog(-1, QList<QString>());
}
2018-01-16 14:09:51 +00:00
void MainWindow::on_actionImportPDB_triggered()
{
QFileDialog dialog(this);
dialog.setWindowTitle(tr("Select PDB file"));
dialog.setNameFilters({ tr("PDB file (*.pdb)"), tr("All files (*)") });
2018-03-21 20:32:32 +00:00
if (!dialog.exec()) {
2018-01-16 14:09:51 +00:00
return;
}
QString pdbFile = dialog.selectedFiles().first();
2018-03-21 20:32:32 +00:00
if (!pdbFile.isEmpty()) {
2018-01-16 14:09:51 +00:00
Core()->loadPDB(pdbFile);
addOutput(tr("%1 loaded.").arg(pdbFile));
}
}
void MainWindow::projectSaved(const QString &name)
{
2018-01-16 14:09:51 +00:00
addOutput(tr("Project saved: ") + name);
}
2018-03-21 20:32:32 +00:00
void MainWindow::addToDockWidgetList(QDockWidget *dockWidget)
{
this->dockWidgets.push_back(dockWidget);
}
2018-03-21 20:32:32 +00:00
void MainWindow::addDockWidgetAction(QDockWidget *dockWidget, QAction *action)
{
this->dockWidgetActions[action] = dockWidget;
}