Projects Management (#66)

* Add TabWidget to NewFileDialog
* Project loading from NewFileDialog
* Projects dir in NewFileDialog
* Add SaveProjectDialog
* Make SaveProjectDialog work, refactor project saving and Notepad
* Add shortcut for Save
* Fix notes loading
* Sort projects in NewFileDialog
* Implement selecting projects dir in SaveProjectDialog
* Fix QAbstractButton include
This commit is contained in:
Florian Märkl 2017-10-21 21:20:10 +02:00 committed by xarkes
parent ae9df7ed5b
commit c73d9a0678
17 changed files with 947 additions and 351 deletions

View File

@ -61,6 +61,7 @@
#include "dialogs/OptionsDialog.h"
#include "widgets/EntrypointWidget.h"
#include "widgets/DisassemblerGraphView.h"
#include "dialogs/SaveProjectDialog.h"
// graphics
#include <QGraphicsEllipseItem>
@ -298,16 +299,8 @@ void MainWindow::initUI()
QShortcut *refresh_shortcut = new QShortcut(QKeySequence(QKeySequence::Refresh), this);
connect(refresh_shortcut, SIGNAL(activated()), this, SLOT(refreshVisibleDockWidgets()));
}
void MainWindow::openFile(const QString &fn, int anal_level, QList<QString> advanced)
{
QString project_name = qhelpers::uniqueProjectName(fn);
if (core->getProjectNames().contains(project_name))
openProject(project_name);
else
openNewFile(fn, anal_level, advanced);
connect(core, SIGNAL(projectSaved(const QString &)), this, SLOT(projectSaved(const QString &)));
}
void MainWindow::openNewFile(const QString &fn, int anal_level, QList<QString> advanced)
@ -327,7 +320,7 @@ void MainWindow::openProject(const QString &project_name)
QString filename = core->cmd("Pi " + project_name);
setFilename(filename.trimmed());
core->cmd("Po " + project_name);
core->openProject(project_name);
initUI();
finalizeOpen();
@ -347,20 +340,9 @@ void MainWindow::finalizeOpen()
core->cmd("fs sections");
updateFrames();
// Restore project notes
QString notes = this->core->cmd("Pnj");
//qDebug() << "Notes:" << notes;
if (notes != "")
if(core->getNotes().isEmpty())
{
QByteArray ba;
ba.append(notes);
notepadDock->setText(QByteArray::fromBase64(ba));
}
else
{
addOutput(tr(" > Adding binary information to notepad"));
notepadDock->setText(tr("# Binary information\n\n") + core->cmd("i") +
core->setNotes(tr("# Binary information\n\n") + core->cmd("i") +
"\n" + core->cmd("ie") + "\n" + core->cmd("iM") + "\n");
}
@ -377,14 +359,27 @@ void MainWindow::finalizeOpen()
notepadDock->highlightPreview();
}
void MainWindow::saveProject()
bool MainWindow::saveProject(bool quit)
{
QString project_name = qhelpers::uniqueProjectName(filename);
core->cmd("Ps " + project_name);
QString notes = this->notepadDock->textToBase64();
//this->add_debug_output(notes);
this->core->cmd("Pnj " + notes);
this->addOutput(tr("Project saved: ") + project_name);
QString projectName = core->getConfig("prj.name");
if (projectName.isEmpty())
{
return saveProjectAs(quit);
}
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::toggleSideBarTheme()
@ -411,15 +406,21 @@ void MainWindow::closeEvent(QCloseEvent *event)
(QMessageBox::StandardButtons)(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel));
//qDebug() << ret;
if (ret == QMessageBox::Save)
{
if(saveProject(true))
{
QSettings settings;
settings.setValue("geometry", saveGeometry());
settings.setValue("size", size());
settings.setValue("pos", pos());
settings.setValue("state", saveState());
saveProject();
QMainWindow::closeEvent(event);
}
else
{
event->ignore();
}
}
else if (ret == QMessageBox::Discard)
{
QSettings settings;
@ -670,7 +671,7 @@ void MainWindow::on_actionRefresh_Panels_triggered()
this->updateFrames();
}
void MainWindow::toggleDockWidget(DockWidget *dock_widget)
void MainWindow::toggleDockWidget(QDockWidget *dock_widget)
{
if (dock_widget->isVisible())
{
@ -808,7 +809,7 @@ void MainWindow::on_actionhide_bottomPannel_triggered()
void MainWindow::sendToNotepad(const QString &txt)
{
this->notepadDock->appendPlainText("```\n" + txt + "\n```");
core->setNotes(core->getNotes() + "```\n" + txt + "\n```");
}
void MainWindow::on_actionFunctionsRename_triggered()
@ -841,6 +842,11 @@ void MainWindow::on_actionSave_triggered()
saveProject();
}
void MainWindow::on_actionSaveAs_triggered()
{
saveProjectAs();
}
void MainWindow::on_actionRun_Script_triggered()
{
QFileDialog dialog(this);
@ -970,3 +976,8 @@ void MainWindow::on_actionAsmOptions_triggered()
auto dialog = new AsmOptionsDialog(this);
dialog->show();
}
void MainWindow::projectSaved(const QString &name)
{
this->addOutput(tr("Project saved: ") + name);
}

View File

@ -53,11 +53,23 @@ public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
void openFile(const QString &fn, int anal_level = -1, QList<QString> advanced = QList<QString>());
void openNewFile(const QString &fn, int anal_level = -1, QList<QString> advanced = QList<QString>());
void openProject(const QString &project_name);
void initUI();
void finalizeOpen();
void saveProject();
/*!
* @param quit whether to show destructive button in dialog
* @return if quit is true, false if the application should not close
*/
bool saveProject(bool quit = false);
/*!
* @param quit whether to show destructive button in dialog
* @return if quit is true, false if the application should not close
*/
bool saveProjectAs(bool quit = false);
void start_web_server();
void closeEvent(QCloseEvent *event) override;
@ -144,6 +156,7 @@ private slots:
void on_actionNew_triggered();
void on_actionSave_triggered();
void on_actionSaveAs_triggered();
void on_actionWhite_Theme_triggered();
@ -165,6 +178,8 @@ private slots:
void on_actionAsmOptions_triggered();
void projectSaved(const QString &name);
private:
CutterCore *core;
DisassemblyWidget *disassemblyDock;
@ -206,10 +221,7 @@ private:
SectionsDock *sectionsDock;
ConsoleWidget *consoleWidget;
void openProject(const QString &project_name);
void openNewFile(const QString &fn, int anal_level, QList<QString> advanced);
void toggleDockWidget(DockWidget *dock_widget);
void toggleDockWidget(QDockWidget *dock_widget);
public:
RVA getCursorAddress() const { return cursorAddress; }

View File

@ -174,7 +174,7 @@ border-top: 0px;
<x>0</x>
<y>0</y>
<width>1013</width>
<height>20</height>
<height>22</height>
</rect>
</property>
<property name="defaultUp">
@ -186,10 +186,10 @@ border-top: 0px;
<widget class="QMenu" name="menuFile">
<property name="geometry">
<rect>
<x>273</x>
<y>136</y>
<width>148</width>
<height>167</height>
<x>419</x>
<y>265</y>
<width>173</width>
<height>206</height>
</rect>
</property>
<property name="title">
@ -199,6 +199,7 @@ border-top: 0px;
<addaction name="actionLoad"/>
<addaction name="separator"/>
<addaction name="actionSave"/>
<addaction name="actionSaveAs"/>
<addaction name="separator"/>
<addaction name="actionRun_Script"/>
<addaction name="separator"/>
@ -419,6 +420,9 @@ QToolButton .svg-icon path {
<property name="text">
<string>Save</string>
</property>
<property name="shortcut">
<string>Ctrl+S</string>
</property>
</action>
<action name="actionUndo">
<property name="text">
@ -979,6 +983,11 @@ QToolButton .svg-icon path {
<string>Disassembly Options</string>
</property>
</action>
<action name="actionSaveAs">
<property name="text">
<string>Save As...</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources>

View File

@ -46,7 +46,6 @@ CutterCore::CutterCore(QObject *parent) :
QObject(parent)
{
r_cons_new(); // initialize console
this->projectPath = "";
this->core_ = r_core_new();
r_core_loadlibs(this->core_, R_CORE_LOADLIBS_ALL, NULL);
// IMPLICIT r_bin_iobind (core_->bin, core_->io);
@ -1219,3 +1218,31 @@ void CutterCore::loadPDB(const QString &file)
{
cmd("idp " + sanitizeStringForCommand(file));
}
void CutterCore::openProject(const QString &name)
{
cmd("Po " + name);
QString notes = QString::fromUtf8(QByteArray::fromBase64(cmd("Pnj").toUtf8()));
setNotes(notes);
}
void CutterCore::saveProject(const QString &name)
{
cmd("Ps " + name);
cmd("Pnj " + notes.toUtf8().toBase64());
emit projectSaved(name);
}
bool CutterCore::isProjectNameValid(const QString &name)
{
// see is_valid_project_name() in libr/core/project.c
static const QRegExp regexp(R"(^[a-zA-Z0-9\\\._:-]{1,}$)");
return regexp.exactMatch(name) && !name.endsWith(".zip") ;
}
void CutterCore::setNotes(const QString &notes)
{
this->notes = notes;
emit notesChanged(this->notes);
}

View File

@ -184,8 +184,6 @@ class CutterCore: public QObject
friend class ccClass;
public:
QString projectPath;
explicit CutterCore(QObject *parent = 0);
~CutterCore();
static CutterCore* getInstance();
@ -267,6 +265,13 @@ public:
QStringList getAnalPluginNames();
QStringList getProjectNames();
void openProject(const QString &name);
void saveProject(const QString &name);
static bool isProjectNameValid(const QString &name);
const QString &getNotes() const { return notes; }
void setNotes(const QString &notes);
QList<RBinPluginDescription> getRBinPluginDescriptions(const QString &type = nullptr);
@ -303,6 +308,9 @@ signals:
void flagsChanged();
void commentsChanged();
void notesChanged(const QString &notes);
void projectSaved(const QString &name);
/*!
* emitted when config regarding disassembly display changes
*/
@ -321,6 +329,8 @@ private:
QString default_cpu;
int default_bits;
QString notes;
RCore *core_;
};

View File

@ -77,7 +77,8 @@ SOURCES += \
widgets/SidebarWidget.cpp \
widgets/HexdumpWidget.cpp \
utils/Configuration.cpp \
utils/Colors.cpp
utils/Colors.cpp \
dialogs/SaveProjectDialog.cpp
HEADERS += \
cutter.h \
@ -126,7 +127,8 @@ HEADERS += \
widgets/SidebarWidget.h \
widgets/HexdumpWidget.h \
utils/Configuration.h \
utils/Colors.h
utils/Colors.h \
dialogs/SaveProjectDialog.h
FORMS += \
widgets/PreviewWidget.ui \
@ -156,7 +158,8 @@ FORMS += \
widgets/StringsWidget.ui \
widgets/SymbolsWidget.ui \
widgets/SidebarWidget.ui \
widgets/HexdumpWidget.ui
widgets/HexdumpWidget.ui \
dialogs/SaveProjectDialog.ui
RESOURCES += \
resources.qrc

View File

@ -64,10 +64,152 @@ NewFileDialog::NewFileDialog(QWidget *parent) :
{
ui->setupUi(this);
setWindowFlags(windowFlags() & (~Qt::WindowContextHelpButtonHint));
ui->recentsList->addAction(ui->actionRemove_item);
ui->recentsList->addAction(ui->actionClear_all);
ui->recentsList->setIconSize(QSize(48, 48));
ui->recentsListWidget->addAction(ui->actionRemove_item);
ui->recentsListWidget->addAction(ui->actionClear_all);
fillRecentFilesList();
bool projectsExist = fillProjectsList();
if(projectsExist)
{
ui->tabWidget->setCurrentWidget(ui->projectsTab);
}
else
{
ui->tabWidget->setCurrentWidget(ui->filesTab);
}
// Hide "create" button until the dialog works
ui->createButton->hide();
ui->loadProjectButton->setEnabled(ui->projectsListWidget->currentItem() != nullptr);
}
NewFileDialog::~NewFileDialog() {}
void NewFileDialog::on_loadFileButton_clicked()
{
loadFile(ui->newFileEdit->text());
}
void NewFileDialog::on_selectFileButton_clicked()
{
QString fileName = QFileDialog::getOpenFileName(this, tr("Select file"), QDir::homePath());
if (!fileName.isEmpty())
{
ui->newFileEdit->setText(fileName);
ui->loadFileButton->setFocus();
}
}
void NewFileDialog::on_selectProjectsDirButton_clicked()
{
QFileDialog dialog(this);
dialog.setFileMode(QFileDialog::DirectoryOnly);
QString currentDir = CutterCore::getInstance()->getConfig("dir.projects");
if(currentDir.startsWith("~"))
{
currentDir = QDir::homePath() + currentDir.mid(1);
}
dialog.setDirectory(currentDir);
dialog.setWindowTitle(tr("Select project path (dir.projects)"));
if(!dialog.exec())
{
return;
}
QString dir = dialog.selectedFiles().first();
if (!dir.isEmpty())
{
CutterCore::getInstance()->setConfig("dir.projects", dir);
fillProjectsList();
}
}
void NewFileDialog::on_loadProjectButton_clicked()
{
QListWidgetItem *item = ui->projectsListWidget->currentItem();
if (item == nullptr)
{
return;
}
loadProject(item->data(Qt::UserRole).toString());
}
void NewFileDialog::on_recentsListWidget_itemClicked(QListWidgetItem *item)
{
QVariant data = item->data(Qt::UserRole);
QString sitem = data.toString();
ui->newFileEdit->setText(sitem);
}
void NewFileDialog::on_recentsListWidget_itemDoubleClicked(QListWidgetItem *item)
{
loadFile(item->data(Qt::UserRole).toString());
}
void NewFileDialog::on_projectsListWidget_itemSelectionChanged()
{
ui->loadProjectButton->setEnabled(ui->projectsListWidget->currentItem() != nullptr);
}
void NewFileDialog::on_projectsListWidget_itemDoubleClicked(QListWidgetItem *item)
{
loadProject(item->data(Qt::UserRole).toString());
}
void NewFileDialog::on_cancelButton_clicked()
{
close();
}
void NewFileDialog::on_actionRemove_item_triggered()
{
// Remove selected item from recents list
QListWidgetItem *item = ui->recentsListWidget->currentItem();
QVariant data = item->data(Qt::UserRole);
QString sitem = data.toString();
QSettings settings;
QStringList files = settings.value("recentFileList").toStringList();
files.removeAll(sitem);
settings.setValue("recentFileList", files);
ui->recentsListWidget->takeItem(ui->recentsListWidget->currentRow());
ui->newFileEdit->clear();
}
void NewFileDialog::on_createButton_clicked()
{
// Close dialog and open create new file dialog
close();
CreateNewDialog *n = new CreateNewDialog(nullptr);
n->exec();
}
void NewFileDialog::on_actionClear_all_triggered()
{
// Clear recent file list
QSettings settings;
QStringList files = settings.value("recentFileList").toStringList();
files.clear();
ui->recentsListWidget->clear();
// TODO: if called from main window its ok, otherwise its not
settings.setValue("recentFileList", files);
ui->newFileEdit->clear();
}
bool NewFileDialog::fillRecentFilesList()
{
// Fill list with recent opened files
QSettings settings;
@ -99,25 +241,45 @@ NewFileDialog::NewFileDialog(QWidget *parent) :
);
//":/img/icons/target.svg"), name );
item->setData(Qt::UserRole, file);
ui->recentsList->addItem(item);
ui->recentsListWidget->addItem(item);
}
}
ui->recentsList->setSortingEnabled(true);
// Hide "create" button until the dialog works
ui->createButton->hide();
// Removes files were deleted from the stringlist. Save it again.
// Removed files were deleted from the stringlist. Save it again.
settings.setValue("recentFileList", files);
return !files.isEmpty();
}
NewFileDialog::~NewFileDialog() {}
bool NewFileDialog::fillProjectsList()
{
CutterCore *core = CutterCore::getInstance();
void NewFileDialog::on_loadFileButton_clicked()
ui->projectsDirEdit->setText(core->getConfig("dir.projects"));
QStringList projects = core->getProjectNames();
projects.sort(Qt::CaseInsensitive);
ui->projectsListWidget->clear();
int i=0;
for(const QString &project : projects)
{
QString info = core->cmd("Pi " + project);
QListWidgetItem *item = new QListWidgetItem(getIconFor(project, i++), project + "\n" + info);
item->setData(Qt::UserRole, project);
ui->projectsListWidget->addItem(item);
}
return !projects.isEmpty();
}
void NewFileDialog::loadFile(const QString &filename)
{
// Check that there is a file selected
QString fname = ui->newFileEdit->text();
QFileInfo checkfile(fname);
QFileInfo checkfile(filename);
if (!checkfile.exists() || !checkfile.isFile())
{
QMessageBox msgBox(this);
@ -129,8 +291,8 @@ void NewFileDialog::on_loadFileButton_clicked()
// Add file to recent file list
QSettings settings;
QStringList files = settings.value("recentFileList").toStringList();
files.removeAll(fname);
files.prepend(fname);
files.removeAll(filename);
files.prepend(filename);
while (files.size() > MaxRecentFiles)
files.removeLast();
@ -140,90 +302,16 @@ void NewFileDialog::on_loadFileButton_clicked()
// Close dialog and open MainWindow/OptionsDialog
MainWindow *main = new MainWindow();
main->openFile(fname);
main->openNewFile(filename);
//OptionsDialog *o = new OptionsDialog(fname);
//o->exec();
}
}
void NewFileDialog::on_newFileButton_clicked()
void NewFileDialog::loadProject(const QString &project)
{
QFileDialog dialog(this);
dialog.setFileMode(QFileDialog::ExistingFile);
dialog.setViewMode(QFileDialog::Detail);
dialog.setDirectory(QDir::home());
QString fileName;
fileName = dialog.getOpenFileName(this, tr("Select file"));
if (!fileName.isEmpty())
{
ui->newFileEdit->setText(fileName);
ui->loadFileButton->setFocus();
}
}
void NewFileDialog::on_recentsList_itemClicked(QListWidgetItem *item)
{
QVariant data = item->data(Qt::UserRole);
QString sitem = data.toString();
ui->newFileEdit->setText(sitem);
}
void NewFileDialog::on_recentsList_itemDoubleClicked(QListWidgetItem *item)
{
// Get selected item to send to options dialog
QVariant data = item->data(Qt::UserRole);
QString sitem = data.toString();
// Close dialog and open OptionsDialog
close();
MainWindow *main = new MainWindow();
main->openFile(sitem);
//OptionsDialog *o = new OptionsDialog(sitem);
//o->exec();
}
void NewFileDialog::on_cancelButton_clicked()
{
close();
}
void NewFileDialog::on_actionRemove_item_triggered()
{
// Remove selected item from recents list
QListWidgetItem *item = ui->recentsList->currentItem();
QVariant data = item->data(Qt::UserRole);
QString sitem = data.toString();
QSettings settings;
QStringList files = settings.value("recentFileList").toStringList();
files.removeAll(sitem);
settings.setValue("recentFileList", files);
ui->recentsList->takeItem(ui->recentsList->currentRow());
ui->newFileEdit->clear();
}
void NewFileDialog::on_createButton_clicked()
{
// Close dialog and open create new file dialog
close();
CreateNewDialog *n = new CreateNewDialog(nullptr);
n->exec();
}
void NewFileDialog::on_actionClear_all_triggered()
{
// Clear recent file list
QSettings settings;
QStringList files = settings.value("recentFileList").toStringList();
files.clear();
ui->recentsList->clear();
// TODO: if called from main window its ok, otherwise its not
settings.setValue("recentFileList", files);
ui->newFileEdit->clear();
main->openProject(project);
}

View File

@ -19,26 +19,40 @@ public:
~NewFileDialog();
private slots:
void on_loadFileButton_clicked();
void on_selectFileButton_clicked();
void on_createButton_clicked();
void on_newFileButton_clicked();
void on_recentsList_itemClicked(QListWidgetItem *item);
void on_recentsList_itemDoubleClicked(QListWidgetItem *item);
void on_selectProjectsDirButton_clicked();
void on_loadProjectButton_clicked();
void on_cancelButton_clicked();
void on_recentsListWidget_itemClicked(QListWidgetItem *item);
void on_recentsListWidget_itemDoubleClicked(QListWidgetItem *item);
void on_projectsListWidget_itemSelectionChanged();
void on_projectsListWidget_itemDoubleClicked(QListWidgetItem *item);
void on_actionRemove_item_triggered();
void on_createButton_clicked();
void on_actionClear_all_triggered();
private:
std::unique_ptr<Ui::NewFileDialog> ui;
/*!
* @return true if list is not empty
*/
bool fillRecentFilesList();
/*!
* @return true if list is not empty
*/
bool fillProjectsList();
void loadFile(const QString &filename);
void loadProject(const QString &project);
static const int MaxRecentFiles = 5;
};

View File

@ -6,15 +6,15 @@
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>450</height>
<width>452</width>
<height>532</height>
</rect>
</property>
<property name="windowTitle">
<string>Open File</string>
</property>
<property name="windowIcon">
<iconset resource="resources.qrc">
<iconset>
<normaloff>:/img/logo-small.png</normaloff>:/img/logo-small.png</iconset>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
@ -42,7 +42,7 @@
<string/>
</property>
<property name="pixmap">
<pixmap resource="resources.qrc">:/img/logo-small.png</pixmap>
<pixmap>:/img/logo-small.png</pixmap>
</property>
<property name="scaledContents">
<bool>false</bool>
@ -96,6 +96,16 @@
<property name="bottomMargin">
<number>5</number>
</property>
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="filesTab">
<attribute name="title">
<string>Open File</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<layout class="QGridLayout" name="gridLayout">
<property name="sizeConstraint">
@ -104,69 +114,8 @@
<property name="horizontalSpacing">
<number>5</number>
</property>
<item row="3" column="0" colspan="2">
<widget class="Line" name="line">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="5" column="0" colspan="2">
<widget class="QListWidget" name="recentsList">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>11</pointsize>
</font>
</property>
<property name="contextMenuPolicy">
<enum>Qt::ActionsContextMenu</enum>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
<property name="verticalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
<property name="resizeMode">
<enum>QListView::Adjust</enum>
</property>
<property name="spacing">
<number>5</number>
</property>
<property name="viewMode">
<enum>QListView::ListMode</enum>
</property>
<property name="uniformItemSizes">
<bool>false</bool>
</property>
<property name="wordWrap">
<bool>false</bool>
</property>
<property name="selectionRectVisible">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="newFileButton">
<widget class="QPushButton" name="selectFileButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
@ -178,20 +127,8 @@
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<widget class="QLabel" name="loadFileLabel">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Previous sessions&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLineEdit" name="newFileEdit">
<property name="font">
<font>
<pointsize>12</pointsize>
</font>
</property>
<property name="frame">
<bool>false</bool>
</property>
@ -215,28 +152,80 @@
</item>
</layout>
</item>
</layout>
<item>
<widget class="Line" name="line">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="buttonBar" stretch="0,0,0,0">
<property name="spacing">
<number>10</number>
<widget class="QListWidget" name="recentsListWidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
<property name="topMargin">
<property name="font">
<font>
<pointsize>11</pointsize>
</font>
</property>
<property name="contextMenuPolicy">
<enum>Qt::ActionsContextMenu</enum>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
<item>
<widget class="QPushButton" name="cancelButton">
<property name="text">
<string>Close</string>
<property name="iconSize">
<size>
<width>48</width>
<height>48</height>
</size>
</property>
<property name="verticalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
<property name="resizeMode">
<enum>QListView::Adjust</enum>
</property>
<property name="spacing">
<number>5</number>
</property>
<property name="viewMode">
<enum>QListView::ListMode</enum>
</property>
<property name="uniformItemSizes">
<bool>false</bool>
</property>
<property name="wordWrap">
<bool>false</bool>
</property>
<property name="selectionRectVisible">
<bool>true</bool>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
@ -265,6 +254,189 @@
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="projectsTab">
<attribute name="title">
<string>Projects</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<layout class="QGridLayout" name="gridLayout_2">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<property name="horizontalSpacing">
<number>5</number>
</property>
<item row="1" column="1">
<widget class="QPushButton" name="selectProjectsDirButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Select</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLineEdit" name="projectsDirEdit">
<property name="frame">
<bool>false</bool>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="projectsDirLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Projects path (dir.projects):&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="Line" name="line_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="projectsListWidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>11</pointsize>
</font>
</property>
<property name="contextMenuPolicy">
<enum>Qt::ActionsContextMenu</enum>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
<property name="iconSize">
<size>
<width>48</width>
<height>48</height>
</size>
</property>
<property name="verticalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
<property name="resizeMode">
<enum>QListView::Adjust</enum>
</property>
<property name="spacing">
<number>5</number>
</property>
<property name="viewMode">
<enum>QListView::ListMode</enum>
</property>
<property name="uniformItemSizes">
<bool>false</bool>
</property>
<property name="wordWrap">
<bool>false</bool>
</property>
<property name="selectionRectVisible">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="loadProjectButton">
<property name="text">
<string>Open</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="buttonBar" stretch="0,0">
<property name="spacing">
<number>10</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<item>
<widget class="QPushButton" name="cancelButton">
<property name="text">
<string>Close</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
<action name="actionRemove_item">
<property name="text">
<string>Remove item</string>
@ -277,7 +449,8 @@
</action>
</widget>
<resources>
<include location="resources.qrc"/>
<include location="../resources.qrc"/>
<include location="../resources.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -0,0 +1,104 @@
#include <QFileDialog>
#include <cutter.h>
#include "SaveProjectDialog.h"
#include "ui_SaveProjectDialog.h"
SaveProjectDialog::SaveProjectDialog(bool quit, QWidget *parent) :
QDialog(parent),
ui(new Ui::SaveProjectDialog)
{
ui->setupUi(this);
CutterCore *core = CutterCore::getInstance();
if (quit)
{
ui->buttonBox->setStandardButtons(QDialogButtonBox::Save
| QDialogButtonBox::Discard
| QDialogButtonBox::Cancel);
}
else
{
ui->buttonBox->setStandardButtons(QDialogButtonBox::Save
| QDialogButtonBox::Cancel);
}
ui->nameEdit->setText(core->getConfig("prj.name"));
ui->projectsDirEdit->setText(core->getConfig("dir.projects"));
ui->filesCheckBox->setChecked(core->getConfigb("prj.files"));
ui->gitCheckBox->setChecked(core->getConfigb("prj.git"));
ui->zipCheckBox->setChecked(core->getConfigb("prj.zip"));
}
SaveProjectDialog::~SaveProjectDialog()
{
}
void SaveProjectDialog::on_selectProjectsDirButton_clicked()
{
QFileDialog dialog(this);
dialog.setFileMode(QFileDialog::DirectoryOnly);
QString currentDir = ui->projectsDirEdit->text();
if(currentDir.startsWith("~"))
{
currentDir = QDir::homePath() + currentDir.mid(1);
}
dialog.setDirectory(currentDir);
dialog.setWindowTitle(tr("Select project path (dir.projects)"));
if(!dialog.exec())
{
return;
}
QString dir = dialog.selectedFiles().first();
if (!dir.isEmpty())
{
ui->projectsDirEdit->setText(dir);
}
}
void SaveProjectDialog::on_buttonBox_clicked(QAbstractButton *button)
{
switch(ui->buttonBox->buttonRole(button))
{
case QDialogButtonBox::DestructiveRole:
QDialog::done(Destructive);
break;
case QDialogButtonBox::RejectRole:
QDialog::done(Rejected);
break;
default:
break;
}
}
void SaveProjectDialog::accept()
{
CutterCore *core = CutterCore::getInstance();
core->setConfig("dir.projects", ui->projectsDirEdit->text().toUtf8().constData());
core->setConfig("prj.files", ui->filesCheckBox->isChecked());
core->setConfig("prj.git", ui->gitCheckBox->isChecked());
core->setConfig("prj.zip", ui->zipCheckBox->isChecked());
QString projectName = ui->nameEdit->text().trimmed();
if(!CutterCore::isProjectNameValid(projectName))
{
QMessageBox::critical(this, tr("Save project"), tr("Invalid project name."));
return;
}
core->saveProject(projectName);
QDialog::done(Saved);
}
void SaveProjectDialog::reject()
{
}

View File

@ -0,0 +1,35 @@
#ifndef SAVEPROJECTDIALOG_H
#define SAVEPROJECTDIALOG_H
#include <QDialog>
#include <QAbstractButton>
#include <memory>
namespace Ui
{
class SaveProjectDialog;
}
class SaveProjectDialog : public QDialog
{
Q_OBJECT
public:
enum Result { Saved, Rejected, Destructive };
explicit SaveProjectDialog(bool quit, QWidget *parent = 0);
~SaveProjectDialog();
virtual void accept() override;
virtual void reject() override;
private slots:
void on_buttonBox_clicked(QAbstractButton *button);
void on_selectProjectsDirButton_clicked();
private:
std::unique_ptr<Ui::SaveProjectDialog> ui;
};
#endif // SAVEPROJECTDIALOG_H

View File

@ -0,0 +1,140 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SaveProjectDialog</class>
<widget class="QDialog" name="SaveProjectDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>506</width>
<height>227</height>
</rect>
</property>
<property name="windowTitle">
<string>Save Project</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="sizeConstraint">
<enum>QLayout::SetMinAndMaxSize</enum>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="nameLabel">
<property name="text">
<string>Project name (prj.name):</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="nameEdit"/>
</item>
</layout>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="nameLabel_2">
<property name="text">
<string>Projects path (dir.projects):</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="projectsDirEdit">
<property name="readOnly">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="selectProjectsDirButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Select</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="filesCheckBox">
<property name="text">
<string>Save the target binary inside the project directory (prj.files)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="gitCheckBox">
<property name="text">
<string>Project is a git repo and saving is committing (prj.git)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="zipCheckBox">
<property name="text">
<string>Use ZIP format for project files (prj.zip)</string>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Save</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>SaveProjectDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>SaveProjectDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -82,7 +82,7 @@ int main(int argc, char *argv[])
else // filename specified as positional argument
{
MainWindow *main = new MainWindow();
main->openFile(args[0], anal_level_specified ? anal_level : -1);
main->openNewFile(args[0], anal_level_specified ? anal_level : -1);
}
return a.exec();

View File

@ -39,12 +39,6 @@ namespace qhelpers
#endif
}
QString uniqueProjectName(const QString &filename)
{
const QByteArray fullHash(QCryptographicHash::hash(filename.toUtf8(), QCryptographicHash::Sha1));
return QFileInfo(filename).fileName() + "_" + fullHash.toHex().left(10);
}
void adjustColumns(QTreeWidget *tw, int columnCount, int padding)
{
const int count = columnCount == 0 ? tw->columnCount() : columnCount;

View File

@ -16,8 +16,6 @@ namespace qhelpers
void normalizeFont(QPlainTextEdit *edit);
void normalizeEditFont(QTextEdit *edit);
QString uniqueProjectName(const QString &filename);
void adjustColumns(QTreeWidget *tw, int columnCount = 0, int padding = 0);
QTreeWidgetItem *appendRow(QTreeWidget *tw, const QString &str, const QString &str2 = QString(),

View File

@ -15,7 +15,7 @@
Notepad::Notepad(MainWindow *main, QWidget *parent) :
DockWidget(parent),
QDockWidget(parent),
ui(new Ui::Notepad)
{
ui->setupUi(this);
@ -40,35 +40,15 @@ Notepad::Notepad(MainWindow *main, QWidget *parent) :
ui->notepadTextEdit->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->notepadTextEdit, SIGNAL(customContextMenuRequested(const QPoint &)),
this, SLOT(showNotepadContextMenu(const QPoint &)));
connect(ui->notepadTextEdit, SIGNAL(textChanged()), this, SLOT(textChanged()));
connect(CutterCore::getInstance(), SIGNAL(notesChanged(const QString &)), this, SLOT(updateNotes(const QString &)));
updateNotes(CutterCore::getInstance()->getNotes());
}
Notepad::~Notepad() {}
void Notepad::setup()
{
}
void Notepad::refresh()
{
// TODO: implement
eprintf("%s - not implemented\n", Q_FUNC_INFO);
}
void Notepad::setText(const QString &str)
{
ui->notepadTextEdit->setPlainText(str);
}
QString Notepad::textToBase64() const
{
return notesTextEdit->toPlainText().toUtf8().toBase64();
}
void Notepad::appendPlainText(const QString &text)
{
notesTextEdit->appendPlainText(text);
}
void Notepad::on_fontButton_clicked()
{
bool ok = true;
@ -359,3 +339,18 @@ void Notepad::on_actionHexdump_function_triggered()
{
ui->previewTextEdit->setPlainText(CutterCore::getInstance()->cmd("pxf @ " + this->addr));
}
void Notepad::updateNotes(const QString &notes)
{
disconnect(ui->notepadTextEdit, SIGNAL(textChanged()), this, SLOT(textChanged()));
ui->notepadTextEdit->setPlainText(notes);
connect(ui->notepadTextEdit, SIGNAL(textChanged()), this, SLOT(textChanged()));
}
void Notepad::textChanged()
{
CutterCore *core = CutterCore::getInstance();
disconnect(core, SIGNAL(notesChanged(const QString &)), this, SLOT(updateNotes(const QString &)));
core->setNotes(ui->notepadTextEdit->toPlainText());
connect(core, SIGNAL(notesChanged(const QString &)), this, SLOT(updateNotes(const QString &)));
}

View File

@ -1,8 +1,8 @@
#ifndef NOTEPAD_H
#define NOTEPAD_H
#include "DockWidget.h"
#include <memory>
#include <QDockWidget>
class MainWindow;
class MdHighlighter;
@ -14,7 +14,7 @@ namespace Ui
class Notepad;
}
class Notepad : public DockWidget
class Notepad : public QDockWidget
{
Q_OBJECT
@ -22,15 +22,6 @@ public:
explicit Notepad(MainWindow *main, QWidget *parent = 0);
~Notepad();
void setup() override;
void refresh() override;
void setText(const QString &str);
QString textToBase64() const;
void appendPlainText(const QString &text);
void highlightPreview();
public slots:
@ -38,39 +29,31 @@ public slots:
private slots:
void on_fontButton_clicked();
void on_boldButton_clicked();
void on_italicsButton_clicked();
void on_h1Button_clicked();
void on_h2Button_clicked();
void on_h3Button_clicked();
void on_undoButton_clicked();
void on_redoButton_clicked();
void on_searchEdit_returnPressed();
void on_searchEdit_textEdited(const QString &arg1);
void on_searchEdit_textChanged(const QString &arg1);
void showNotepadContextMenu(const QPoint &pt);
void on_actionDisassmble_bytes_triggered();
void on_actionDisassmble_function_triggered();
void on_actionHexdump_bytes_triggered();
void on_actionCompact_Hexdump_triggered();
void on_actionHexdump_function_triggered();
void updateNotes(const QString &notes);
void textChanged();
private:
std::unique_ptr<Ui::Notepad> ui;
MdHighlighter *highlighter;