mirror of
https://github.com/rizinorg/cutter.git
synced 2024-12-18 10:56:11 +00:00
Add Support for new Projects (#3)
This commit is contained in:
parent
78dcba4c26
commit
85042000e8
2
rizin
2
rizin
@ -1 +1 @@
|
||||
Subproject commit 8b30c4f0d7282009e52099764e15b686c4d08654
|
||||
Subproject commit c5021f7c8a60f9c95b29a3f75922b17f3ec38bc3
|
@ -344,7 +344,6 @@ SOURCES += \
|
||||
widgets/HexdumpWidget.cpp \
|
||||
common/Configuration.cpp \
|
||||
common/Colors.cpp \
|
||||
dialogs/SaveProjectDialog.cpp \
|
||||
common/TempConfig.cpp \
|
||||
common/SvgIconEngine.cpp \
|
||||
common/SyntaxHighlighter.cpp \
|
||||
@ -495,7 +494,6 @@ HEADERS += \
|
||||
widgets/HexdumpWidget.h \
|
||||
common/Configuration.h \
|
||||
common/Colors.h \
|
||||
dialogs/SaveProjectDialog.h \
|
||||
common/TempConfig.h \
|
||||
common/SvgIconEngine.h \
|
||||
common/SyntaxHighlighter.h \
|
||||
@ -621,7 +619,7 @@ FORMS += \
|
||||
dialogs/RemoteDebugDialog.ui \
|
||||
dialogs/NativeDebugDialog.ui \
|
||||
dialogs/XrefsDialog.ui \
|
||||
dialogs/NewfileDialog.ui \
|
||||
dialogs/NewFileDialog.ui \
|
||||
dialogs/InitialOptionsDialog.ui \
|
||||
dialogs/EditFunctionDialog.ui \
|
||||
core/MainWindow.ui \
|
||||
@ -631,7 +629,6 @@ FORMS += \
|
||||
widgets/FlagsWidget.ui \
|
||||
widgets/StringsWidget.ui \
|
||||
widgets/HexdumpWidget.ui \
|
||||
dialogs/SaveProjectDialog.ui \
|
||||
dialogs/preferences/PreferencesDialog.ui \
|
||||
dialogs/preferences/AppearanceOptionsWidget.ui \
|
||||
dialogs/preferences/GraphOptionsWidget.ui \
|
||||
|
@ -169,22 +169,6 @@ void Configuration::loadInitial()
|
||||
#endif
|
||||
}
|
||||
|
||||
QString Configuration::getDirProjects()
|
||||
{
|
||||
auto projectsDir = s.value("dir.projects").toString();
|
||||
if (projectsDir.isEmpty()) {
|
||||
projectsDir = Core()->getConfig("dir.projects");
|
||||
setDirProjects(projectsDir);
|
||||
}
|
||||
|
||||
return QDir::toNativeSeparators(projectsDir);
|
||||
}
|
||||
|
||||
void Configuration::setDirProjects(const QString &dir)
|
||||
{
|
||||
s.setValue("dir.projects", QDir::toNativeSeparators(dir));
|
||||
}
|
||||
|
||||
QString Configuration::getRecentFolder()
|
||||
{
|
||||
QString recentFolder = s.value("dir.recentFolder", QDir::homePath()).toString();
|
||||
@ -789,4 +773,32 @@ bool Configuration::getGraphBlockEntryOffset()
|
||||
void Configuration::setGraphBlockEntryOffset(bool enabled)
|
||||
{
|
||||
s.setValue("graphBlockEntryOffset", enabled);
|
||||
}
|
||||
}
|
||||
|
||||
QStringList Configuration::getRecentFiles() const
|
||||
{
|
||||
return s.value("recentFileList").toStringList();
|
||||
}
|
||||
|
||||
void Configuration::setRecentFiles(const QStringList &list)
|
||||
{
|
||||
s.setValue("recentFileList", list);
|
||||
}
|
||||
|
||||
QStringList Configuration::getRecentProjects() const
|
||||
{
|
||||
return s.value("recentProjectsList").toStringList();
|
||||
}
|
||||
|
||||
void Configuration::setRecentProjects(const QStringList &list)
|
||||
{
|
||||
s.setValue("recentProjectsList", list);
|
||||
}
|
||||
|
||||
void Configuration::addRecentProject(QString file)
|
||||
{
|
||||
QStringList files = getRecentProjects();
|
||||
files.removeAll(file);
|
||||
files.prepend(file);
|
||||
setRecentProjects(files);
|
||||
}
|
||||
|
@ -114,9 +114,6 @@ public:
|
||||
#endif
|
||||
QSyntaxHighlighter *createSyntaxHighlighter(QTextDocument *document);
|
||||
|
||||
QString getDirProjects();
|
||||
void setDirProjects(const QString &dir);
|
||||
|
||||
QString getRecentFolder();
|
||||
void setRecentFolder(const QString &dir);
|
||||
|
||||
@ -208,6 +205,19 @@ public:
|
||||
void setOutputRedirectionEnabled(bool enabled);
|
||||
bool getOutputRedirectionEnabled() const;
|
||||
|
||||
/**
|
||||
* @brief Recently opened binaries, as shown in NewFileDialog.
|
||||
*/
|
||||
QStringList getRecentFiles() const;
|
||||
void setRecentFiles(const QStringList &list);
|
||||
|
||||
/**
|
||||
* @brief Recently opened projects, as shown in NewFileDialog.
|
||||
*/
|
||||
QStringList getRecentProjects() const;
|
||||
void setRecentProjects(const QStringList &list);
|
||||
void addRecentProject(QString file);
|
||||
|
||||
public slots:
|
||||
void refreshFont();
|
||||
signals:
|
||||
|
@ -28,7 +28,7 @@ static bool migrateSettingsPre18(QSettings &newSettings)
|
||||
return true;
|
||||
}
|
||||
|
||||
#define CUTTER_SETTINGS_VERSION_CURRENT 5
|
||||
#define CUTTER_SETTINGS_VERSION_CURRENT 6
|
||||
#define CUTTER_SETTINGS_VERSION_KEY "version"
|
||||
|
||||
/*
|
||||
@ -123,6 +123,11 @@ static void migrateSettingsTo5(QSettings &settings)
|
||||
renameAsmOption(settings, "asm.var.sub", "asm.sub.var");
|
||||
}
|
||||
|
||||
static void migrateSettingsTo6(QSettings &settings)
|
||||
{
|
||||
settings.remove("dir.projects");
|
||||
}
|
||||
|
||||
void Cutter::initializeSettings()
|
||||
{
|
||||
QSettings::setDefaultFormat(QSettings::IniFormat);
|
||||
@ -150,6 +155,8 @@ void Cutter::initializeSettings()
|
||||
migrateSettingsTo4(settings); break;
|
||||
case 5:
|
||||
migrateSettingsTo5(settings); break;
|
||||
case 6:
|
||||
migrateSettingsTo6(settings); break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -18,9 +18,10 @@
|
||||
#include "common/Json.h"
|
||||
#include "core/Cutter.h"
|
||||
#include "Decompiler.h"
|
||||
#include "rz_asm.h"
|
||||
#include "rz_cmd.h"
|
||||
#include "sdb.h"
|
||||
|
||||
#include <rz_asm.h>
|
||||
#include <rz_cmd.h>
|
||||
#include <sdb.h>
|
||||
|
||||
Q_GLOBAL_STATIC(CutterCore, uniqueInstance)
|
||||
|
||||
@ -2415,11 +2416,6 @@ QStringList CutterCore::getAnalPluginNames()
|
||||
return ret;
|
||||
}
|
||||
|
||||
QStringList CutterCore::getProjectNames()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
QList<RzBinPluginDescription> CutterCore::getRBinPluginDescriptions(const QString &type)
|
||||
{
|
||||
QList<RzBinPluginDescription> ret;
|
||||
@ -3635,36 +3631,6 @@ void CutterCore::loadPDB(const QString &file)
|
||||
cmdRaw("idp " + sanitizeStringForCommand(file));
|
||||
}
|
||||
|
||||
void CutterCore::openProject(const QString &name)
|
||||
{
|
||||
cmdRaw("Po " + name);
|
||||
|
||||
QString notes = QString::fromUtf8(QByteArray::fromBase64(cmdRaw("Pnj").toUtf8()));
|
||||
}
|
||||
|
||||
void CutterCore::saveProject(const QString &name)
|
||||
{
|
||||
const QString &rv = cmdRaw("Ps " + name.trimmed()).trimmed();
|
||||
const bool ok = rv == name.trimmed();
|
||||
cmdRaw(QString("Pnj %1").arg(QString(notes.toUtf8().toBase64())));
|
||||
emit projectSaved(ok, name);
|
||||
}
|
||||
|
||||
void CutterCore::deleteProject(const QString &name)
|
||||
{
|
||||
cmdRaw("Pd " + name);
|
||||
}
|
||||
|
||||
bool CutterCore::isProjectNameValid(const QString &name)
|
||||
{
|
||||
// see is_valid_project_name() in libr/core/project.
|
||||
|
||||
QString pattern(R"(^[a-zA-Z0-9\\\._:-]{1,}$)");
|
||||
// The below construct mimics the behaviour of QRegexP::exactMatch(), which was here before
|
||||
static const QRegularExpression regexp("\\A(?:" + pattern + ")\\z");
|
||||
return regexp.match(name).hasMatch() && !name.endsWith(".zip") ;
|
||||
}
|
||||
|
||||
QList<DisassemblyLine> CutterCore::disassembleLines(RVA offset, int lines)
|
||||
{
|
||||
QJsonArray array = cmdj(QString("pdJ ") + QString::number(lines) + QString(" @ ") + QString::number(
|
||||
|
@ -28,6 +28,8 @@ class R2TaskDialog;
|
||||
#include "common/Helpers.h"
|
||||
#include "dialogs/R2TaskDialog.h"
|
||||
|
||||
#include <rz_project.h>
|
||||
|
||||
#define Core() (CutterCore::instance())
|
||||
|
||||
class RzCoreLocked;
|
||||
@ -473,13 +475,6 @@ public:
|
||||
QStringList getAsmPluginNames();
|
||||
QStringList getAnalPluginNames();
|
||||
|
||||
/* Projects */
|
||||
QStringList getProjectNames();
|
||||
void openProject(const QString &name);
|
||||
void saveProject(const QString &name);
|
||||
void deleteProject(const QString &name);
|
||||
static bool isProjectNameValid(const QString &name);
|
||||
|
||||
/* Widgets */
|
||||
QList<RzBinPluginDescription> getRBinPluginDescriptions(const QString &type = QString());
|
||||
QList<RzIOPluginDescription> getRIOPluginDescriptions();
|
||||
@ -673,8 +668,6 @@ signals:
|
||||
|
||||
void attachedRemote(bool successfully);
|
||||
|
||||
void projectSaved(bool successfully, const QString &name);
|
||||
|
||||
void ioCacheChanged(bool newval);
|
||||
void writeModeChanged(bool newval);
|
||||
void ioModeChanged();
|
||||
@ -708,8 +701,6 @@ signals:
|
||||
void showMemoryWidgetRequested();
|
||||
|
||||
private:
|
||||
QString notes;
|
||||
|
||||
/**
|
||||
* Internal reference to the RzCore.
|
||||
* NEVER use this directly! Always use the CORE_LOCK(); macro and access it like core->...
|
||||
|
@ -20,7 +20,6 @@
|
||||
#include "dialogs/WelcomeDialog.h"
|
||||
#include "dialogs/NewFileDialog.h"
|
||||
#include "dialogs/InitialOptionsDialog.h"
|
||||
#include "dialogs/SaveProjectDialog.h"
|
||||
#include "dialogs/CommentsDialog.h"
|
||||
#include "dialogs/AboutDialog.h"
|
||||
#include "dialogs/preferences/PreferencesDialog.h"
|
||||
@ -115,6 +114,8 @@
|
||||
#include <QGraphicsScene>
|
||||
#include <QGraphicsView>
|
||||
|
||||
#define PROJECT_FILE_FILTER tr("Rizin Project (*.rzdb)")
|
||||
|
||||
template<class T>
|
||||
T *getNewInstance(MainWindow *m) { return new T(m); }
|
||||
|
||||
@ -189,8 +190,6 @@ void MainWindow::initUI()
|
||||
connect(ui->actionZoomOut, &QAction::triggered, this, &MainWindow::onZoomOut);
|
||||
connect(ui->actionZoomReset, &QAction::triggered, this, &MainWindow::onZoomReset);
|
||||
|
||||
connect(core, &CutterCore::projectSaved, this, &MainWindow::projectSaved);
|
||||
|
||||
connect(core, &CutterCore::toggleDebugView, this, &MainWindow::toggleDebugView);
|
||||
|
||||
connect(core, &CutterCore::newMessage,
|
||||
@ -604,14 +603,32 @@ void MainWindow::displayInitialOptionsDialog(const InitialOptions &options, bool
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::openProject(const QString &project_name)
|
||||
bool MainWindow::openProject(const QString &file)
|
||||
{
|
||||
QString filename = core->cmdRaw("Pi " + project_name);
|
||||
setFilename(filename.trimmed());
|
||||
RzProjectErr err;
|
||||
RzList *res = rz_list_new();
|
||||
{
|
||||
RzCoreLocked core(Core());
|
||||
err = rz_project_load_file(core, file.toUtf8().constData(), true, res);
|
||||
}
|
||||
if (err != RZ_PROJECT_ERR_SUCCESS) {
|
||||
const char *s = rz_project_err_message(err);
|
||||
QString msg = tr("Failed to open project: %1").arg(QString::fromUtf8(s));
|
||||
RzListIter *it;
|
||||
CutterRListForeach(res, it, const char, s) {
|
||||
msg += "\n" + QString::fromUtf8(s);
|
||||
}
|
||||
QMessageBox::critical(this, tr("Open Project"), msg);
|
||||
rz_list_free(res);
|
||||
return false;
|
||||
}
|
||||
|
||||
core->openProject(project_name);
|
||||
Config()->addRecentProject(file);
|
||||
|
||||
rz_list_free(res);
|
||||
setFilename(file.trimmed());
|
||||
finalizeOpen();
|
||||
return true;
|
||||
}
|
||||
|
||||
void MainWindow::finalizeOpen()
|
||||
@ -668,21 +685,52 @@ void MainWindow::finalizeOpen()
|
||||
}
|
||||
}
|
||||
|
||||
bool MainWindow::saveProject(bool quit)
|
||||
RzProjectErr MainWindow::saveProject(bool *canceled)
|
||||
{
|
||||
QString projectName = core->getConfig("prj.name");
|
||||
if (projectName.isEmpty()) {
|
||||
return saveProjectAs(quit);
|
||||
} else {
|
||||
core->saveProject(projectName);
|
||||
return true;
|
||||
QString file = core->getConfig("prj.file");
|
||||
if (file.isEmpty()) {
|
||||
return saveProjectAs(canceled);
|
||||
}
|
||||
if (canceled) {
|
||||
*canceled = false;
|
||||
}
|
||||
RzProjectErr err = rz_project_save_file(RzCoreLocked(core), file.toUtf8().constData());
|
||||
if (err == RZ_PROJECT_ERR_SUCCESS) {
|
||||
Config()->addRecentProject(file);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
bool MainWindow::saveProjectAs(bool quit)
|
||||
RzProjectErr MainWindow::saveProjectAs(bool *canceled)
|
||||
{
|
||||
SaveProjectDialog dialog(quit, this);
|
||||
return SaveProjectDialog::Rejected != dialog.exec();
|
||||
QString dir = core->getConfig("prj.file");
|
||||
if (dir.isEmpty()) {
|
||||
dir = QDir(filename).dirName();
|
||||
}
|
||||
QString file = QFileDialog::getSaveFileName(this, tr("Save Project"), dir, PROJECT_FILE_FILTER);
|
||||
if (file.isEmpty()) {
|
||||
if (canceled) {
|
||||
*canceled = true;
|
||||
}
|
||||
return RZ_PROJECT_ERR_SUCCESS;
|
||||
}
|
||||
if (canceled) {
|
||||
*canceled = false;
|
||||
}
|
||||
RzProjectErr err = rz_project_save_file(RzCoreLocked(core), file.toUtf8().constData());
|
||||
if (err == RZ_PROJECT_ERR_SUCCESS) {
|
||||
Config()->addRecentProject(file);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
void MainWindow::showProjectSaveError(RzProjectErr err)
|
||||
{
|
||||
if (err == RZ_PROJECT_ERR_SUCCESS) {
|
||||
return;
|
||||
}
|
||||
const char *s = rz_project_err_message(err);
|
||||
QMessageBox::critical(this, tr("Save Project"), tr("Failed to save project: %1").arg(QString::fromUtf8(s)));
|
||||
}
|
||||
|
||||
void MainWindow::refreshOmniBar(const QStringList &flags)
|
||||
@ -715,9 +763,17 @@ void MainWindow::closeEvent(QCloseEvent *event)
|
||||
return;
|
||||
}
|
||||
|
||||
if (ret == QMessageBox::Save && !saveProject(true)) {
|
||||
event->ignore();
|
||||
return;
|
||||
if (ret == QMessageBox::Save) {
|
||||
bool canceled;
|
||||
RzProjectErr save_err = saveProject(&canceled);
|
||||
if (canceled) {
|
||||
event->ignore();
|
||||
return;
|
||||
} else if (save_err != RZ_PROJECT_ERR_SUCCESS) {
|
||||
event->ignore();
|
||||
showProjectSaveError(save_err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!core->currentlyDebugging) {
|
||||
@ -1465,12 +1521,12 @@ void MainWindow::on_actionNew_triggered()
|
||||
|
||||
void MainWindow::on_actionSave_triggered()
|
||||
{
|
||||
saveProject();
|
||||
showProjectSaveError(saveProject(nullptr));
|
||||
}
|
||||
|
||||
void MainWindow::on_actionSaveAs_triggered()
|
||||
{
|
||||
saveProjectAs();
|
||||
showProjectSaveError(saveProjectAs(nullptr));
|
||||
}
|
||||
|
||||
void MainWindow::on_actionRun_Script_triggered()
|
||||
@ -1709,14 +1765,6 @@ void MainWindow::seekToFunctionStart()
|
||||
Core()->seek(Core()->getFunctionStart(Core()->getOffset()));
|
||||
}
|
||||
|
||||
void MainWindow::projectSaved(bool successfully, const QString &name)
|
||||
{
|
||||
if (successfully)
|
||||
core->message(tr("Project saved: %1").arg(name));
|
||||
else
|
||||
core->message(tr("Failed to save project: %1").arg(name));
|
||||
}
|
||||
|
||||
void MainWindow::toggleDebugView()
|
||||
{
|
||||
MemoryWidgetType memType = getMemoryWidgetTypeToRestore();
|
||||
|
@ -73,19 +73,11 @@ public:
|
||||
void displayNewFileDialog();
|
||||
void displayWelcomeDialog();
|
||||
void closeNewFileDialog();
|
||||
void openProject(const QString &project_name);
|
||||
bool openProject(const QString &project_name);
|
||||
|
||||
/**
|
||||
* @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 false if the application should not close
|
||||
*/
|
||||
bool saveProjectAs(bool quit = false);
|
||||
RzProjectErr saveProject(bool *canceled);
|
||||
RzProjectErr saveProjectAs(bool *canceled);
|
||||
void showProjectSaveError(RzProjectErr err);
|
||||
|
||||
void closeEvent(QCloseEvent *event) override;
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
@ -197,8 +189,6 @@ private slots:
|
||||
|
||||
void on_actionGrouped_dock_dragging_triggered(bool checked);
|
||||
|
||||
void projectSaved(bool successfully, const QString &name);
|
||||
|
||||
void updateTasksIndicator();
|
||||
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
|
@ -276,7 +276,7 @@
|
||||
</action>
|
||||
<action name="actionSave">
|
||||
<property name="text">
|
||||
<string>Save</string>
|
||||
<string>Save Project</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+S</string>
|
||||
@ -714,7 +714,7 @@
|
||||
</action>
|
||||
<action name="actionSaveAs">
|
||||
<property name="text">
|
||||
<string>Save As...</string>
|
||||
<string>Save Project As...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionGraph">
|
||||
|
@ -2,7 +2,7 @@
|
||||
#include "core/MainWindow.h"
|
||||
#include "dialogs/NewFileDialog.h"
|
||||
#include "dialogs/AboutDialog.h"
|
||||
#include "ui_NewfileDialog.h"
|
||||
#include "ui_NewFileDialog.h"
|
||||
#include "common/Helpers.h"
|
||||
#include "common/HighDpiPixmap.h"
|
||||
|
||||
@ -62,11 +62,9 @@ NewFileDialog::NewFileDialog(MainWindow *main) :
|
||||
ui->recentsListWidget->addAction(ui->actionRemove_item);
|
||||
ui->recentsListWidget->addAction(ui->actionClear_all);
|
||||
ui->projectsListWidget->addAction(ui->actionRemove_project);
|
||||
ui->projectsListWidget->addAction(ui->actionClearProjects);
|
||||
ui->logoSvgWidget->load(Config()->getLogoFile());
|
||||
|
||||
// radare2 does not seem to save this config so here we load this manually
|
||||
Core()->setConfig("dir.projects", Config()->getDirProjects());
|
||||
|
||||
fillRecentFilesList();
|
||||
fillIOPluginsList();
|
||||
fillProjectsList();
|
||||
@ -74,10 +72,10 @@ NewFileDialog::NewFileDialog(MainWindow *main) :
|
||||
// Set last clicked tab
|
||||
ui->tabWidget->setCurrentIndex(Config()->getNewFileLastClicked());
|
||||
|
||||
ui->loadProjectButton->setEnabled(ui->projectsListWidget->currentItem() != nullptr);
|
||||
|
||||
/* Set focus on the TextInput */
|
||||
ui->newFileEdit->setFocus();
|
||||
|
||||
updateLoadProjectButton();
|
||||
}
|
||||
|
||||
NewFileDialog::~NewFileDialog() {}
|
||||
@ -100,41 +98,20 @@ void NewFileDialog::on_selectFileButton_clicked()
|
||||
}
|
||||
}
|
||||
|
||||
void NewFileDialog::on_selectProjectsDirButton_clicked()
|
||||
void NewFileDialog::on_selectProjectFileButton_clicked()
|
||||
{
|
||||
auto currentDir = Config()->getDirProjects();
|
||||
const QString &fileName = QDir::toNativeSeparators(
|
||||
QFileDialog::getOpenFileName(this, tr("Open Project")));
|
||||
|
||||
if (currentDir.startsWith("~")) {
|
||||
currentDir = QDir::homePath() + currentDir.mid(1);
|
||||
if (!fileName.isEmpty()) {
|
||||
ui->projectFileEdit->setText(fileName);
|
||||
ui->loadProjectButton->setFocus();
|
||||
}
|
||||
const QString &dir = QDir::toNativeSeparators(QFileDialog::getExistingDirectory(this,
|
||||
tr("Select project path (dir.projects)"),
|
||||
currentDir));
|
||||
|
||||
if (dir.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (!QFileInfo(dir).isWritable()) {
|
||||
QMessageBox::critical(this, tr("Permission denied"),
|
||||
tr("You do not have write access to <b>%1</b>")
|
||||
.arg(dir));
|
||||
return;
|
||||
}
|
||||
|
||||
Config()->setDirProjects(dir);
|
||||
Core()->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());
|
||||
loadProject(ui->projectFileEdit->text());
|
||||
}
|
||||
|
||||
void NewFileDialog::on_shellcodeButton_clicked()
|
||||
@ -165,9 +142,14 @@ void NewFileDialog::on_recentsListWidget_itemDoubleClicked(QListWidgetItem *item
|
||||
loadFile(item->data(Qt::UserRole).toString());
|
||||
}
|
||||
|
||||
void NewFileDialog::on_projectsListWidget_itemSelectionChanged()
|
||||
void NewFileDialog::on_projectFileEdit_textChanged()
|
||||
{
|
||||
ui->loadProjectButton->setEnabled(ui->projectsListWidget->currentItem() != nullptr);
|
||||
updateLoadProjectButton();
|
||||
}
|
||||
|
||||
void NewFileDialog::on_projectsListWidget_itemClicked(QListWidgetItem *item)
|
||||
{
|
||||
ui->projectFileEdit->setText(item->data(Qt::UserRole).toString());
|
||||
}
|
||||
|
||||
void NewFileDialog::on_projectsListWidget_itemDoubleClicked(QListWidgetItem *item)
|
||||
@ -186,63 +168,43 @@ void NewFileDialog::on_actionRemove_item_triggered()
|
||||
{
|
||||
// Remove selected item from recents list
|
||||
QListWidgetItem *item = ui->recentsListWidget->currentItem();
|
||||
|
||||
if (item == nullptr)
|
||||
if (item == nullptr) {
|
||||
return;
|
||||
|
||||
QVariant data = item->data(Qt::UserRole);
|
||||
QString sitem = data.toString();
|
||||
|
||||
QSettings settings;
|
||||
QStringList files = settings.value("recentFileList").toStringList();
|
||||
}
|
||||
QString sitem = item->data(Qt::UserRole).toString();
|
||||
QStringList files = Config()->getRecentFiles();
|
||||
files.removeAll(sitem);
|
||||
settings.setValue("recentFileList", files);
|
||||
|
||||
Config()->setRecentFiles(files);
|
||||
ui->recentsListWidget->takeItem(ui->recentsListWidget->currentRow());
|
||||
|
||||
ui->newFileEdit->clear();
|
||||
}
|
||||
|
||||
void NewFileDialog::on_actionClear_all_triggered()
|
||||
{
|
||||
// Clear recent file list
|
||||
QSettings settings;
|
||||
QStringList files = settings.value("recentFileList").toStringList();
|
||||
files.clear();
|
||||
|
||||
Config()->setRecentFiles({});
|
||||
ui->recentsListWidget->clear();
|
||||
// TODO: if called from main window its ok, otherwise its not
|
||||
settings.setValue("recentFileList", files);
|
||||
ui->newFileEdit->clear();
|
||||
}
|
||||
|
||||
void NewFileDialog::on_actionRemove_project_triggered()
|
||||
{
|
||||
CutterCore *core = Core();
|
||||
|
||||
QListWidgetItem *item = ui->projectsListWidget->currentItem();
|
||||
|
||||
if (item == nullptr)
|
||||
if (item == nullptr) {
|
||||
return;
|
||||
|
||||
QVariant data = item->data(Qt::UserRole);
|
||||
QString sitem = data.toString();
|
||||
|
||||
// Confirmation box
|
||||
QMessageBox msgBox(this);
|
||||
msgBox.setText(tr("Delete the project \"%1\" from disk ?").arg(sitem));
|
||||
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
|
||||
int ret = msgBox.exec();
|
||||
|
||||
switch (ret) {
|
||||
case QMessageBox::Yes:
|
||||
core->deleteProject(sitem);
|
||||
ui->projectsListWidget->takeItem(ui->projectsListWidget->currentRow());
|
||||
break;
|
||||
case QMessageBox::No:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
QString sitem = item->data(Qt::UserRole).toString();
|
||||
QStringList files = Config()->getRecentProjects();
|
||||
files.removeAll(sitem);
|
||||
Config()->setRecentProjects(files);
|
||||
ui->projectsListWidget->takeItem(ui->projectsListWidget->currentRow());
|
||||
ui->projectFileEdit->clear();
|
||||
}
|
||||
|
||||
void NewFileDialog::on_actionClearProjects_triggered()
|
||||
{
|
||||
Config()->setRecentProjects({});
|
||||
ui->projectsListWidget->clear();
|
||||
ui->projectFileEdit->clear();
|
||||
}
|
||||
|
||||
void NewFileDialog::dragEnterEvent(QDragEnterEvent *event)
|
||||
@ -265,14 +227,15 @@ void NewFileDialog::dropEvent(QDropEvent *event)
|
||||
loadFile(event->mimeData()->urls().first().toLocalFile());
|
||||
}
|
||||
|
||||
bool NewFileDialog::fillRecentFilesList()
|
||||
/*
|
||||
* @brief Add the existing files from the list to the widget.
|
||||
* @return the list of files that actually exist
|
||||
*/
|
||||
static QStringList fillFilesList(QListWidget *widget, const QStringList &files)
|
||||
{
|
||||
// Fill list with recent opened files
|
||||
QSettings settings;
|
||||
QStringList updatedFiles = files;
|
||||
|
||||
QStringList files = settings.value("recentFileList").toStringList();
|
||||
|
||||
QMutableListIterator<QString> it(files);
|
||||
QMutableListIterator<QString> it(updatedFiles);
|
||||
int i = 0;
|
||||
while (it.hasNext()) {
|
||||
// Get the file name
|
||||
@ -296,40 +259,27 @@ bool NewFileDialog::fillRecentFilesList()
|
||||
text
|
||||
);
|
||||
item->setData(Qt::UserRole, fullpath);
|
||||
ui->recentsListWidget->addItem(item);
|
||||
widget->addItem(item);
|
||||
}
|
||||
}
|
||||
return updatedFiles;
|
||||
}
|
||||
|
||||
bool NewFileDialog::fillRecentFilesList()
|
||||
{
|
||||
QStringList files = Config()->getRecentFiles();
|
||||
files = fillFilesList(ui->recentsListWidget, files);
|
||||
// Removed files were deleted from the stringlist. Save it again.
|
||||
settings.setValue("recentFileList", files);
|
||||
|
||||
Config()->setRecentFiles(files);
|
||||
return !files.isEmpty();
|
||||
}
|
||||
|
||||
bool NewFileDialog::fillProjectsList()
|
||||
{
|
||||
CutterCore *core = Core();
|
||||
|
||||
auto currentDir = Config()->getDirProjects();
|
||||
|
||||
ui->projectsDirEdit->setText(currentDir);
|
||||
|
||||
QStringList projects = core->getProjectNames();
|
||||
projects.sort(Qt::CaseInsensitive);
|
||||
|
||||
ui->projectsListWidget->clear();
|
||||
|
||||
int i = 0;
|
||||
for (const QString &project : projects) {
|
||||
QString info = QDir::toNativeSeparators(core->cmdRaw("Pi " + project));
|
||||
|
||||
QListWidgetItem *item = new QListWidgetItem(getIconFor(project, i++), project + "\n" + info);
|
||||
|
||||
item->setData(Qt::UserRole, project);
|
||||
ui->projectsListWidget->addItem(item);
|
||||
}
|
||||
|
||||
return !projects.isEmpty();
|
||||
QStringList files = Config()->getRecentProjects();
|
||||
files = fillFilesList(ui->projectsListWidget, files);
|
||||
Config()->setRecentProjects(files);
|
||||
return !files.isEmpty();
|
||||
}
|
||||
|
||||
void NewFileDialog::fillIOPluginsList()
|
||||
@ -357,6 +307,11 @@ void NewFileDialog::fillIOPluginsList()
|
||||
}
|
||||
}
|
||||
|
||||
void NewFileDialog::updateLoadProjectButton()
|
||||
{
|
||||
ui->loadProjectButton->setEnabled(!ui->projectFileEdit->text().trimmed().isEmpty());
|
||||
}
|
||||
|
||||
void NewFileDialog::loadFile(const QString &filename)
|
||||
{
|
||||
const QString &nativeFn = QDir::toNativeSeparators(filename);
|
||||
@ -370,13 +325,12 @@ void NewFileDialog::loadFile(const QString &filename)
|
||||
|
||||
// Add file to recent file list
|
||||
QSettings settings;
|
||||
QStringList files = settings.value("recentFileList").toStringList();
|
||||
QStringList files = Config()->getRecentFiles();
|
||||
files.removeAll(nativeFn);
|
||||
files.prepend(nativeFn);
|
||||
while (files.size() > MaxRecentFiles)
|
||||
files.removeLast();
|
||||
|
||||
settings.setValue("recentFileList", files);
|
||||
Config()->setRecentFiles(files);
|
||||
|
||||
// Close dialog and open MainWindow/InitialOptionsDialog
|
||||
QString ioFile = "";
|
||||
@ -394,8 +348,9 @@ void NewFileDialog::loadFile(const QString &filename)
|
||||
void NewFileDialog::loadProject(const QString &project)
|
||||
{
|
||||
MainWindow *main = new MainWindow();
|
||||
main->openProject(project);
|
||||
|
||||
if (!main->openProject(project)) {
|
||||
return;
|
||||
}
|
||||
close();
|
||||
}
|
||||
|
||||
|
@ -22,8 +22,8 @@ public:
|
||||
private slots:
|
||||
void on_loadFileButton_clicked();
|
||||
void on_selectFileButton_clicked();
|
||||
void on_selectProjectFileButton_clicked();
|
||||
|
||||
void on_selectProjectsDirButton_clicked();
|
||||
void on_loadProjectButton_clicked();
|
||||
void on_shellcodeButton_clicked();
|
||||
|
||||
@ -32,12 +32,14 @@ private slots:
|
||||
void on_recentsListWidget_itemClicked(QListWidgetItem *item);
|
||||
void on_recentsListWidget_itemDoubleClicked(QListWidgetItem *item);
|
||||
|
||||
void on_projectsListWidget_itemSelectionChanged();
|
||||
void on_projectFileEdit_textChanged();
|
||||
void on_projectsListWidget_itemClicked(QListWidgetItem *item);
|
||||
void on_projectsListWidget_itemDoubleClicked(QListWidgetItem *item);
|
||||
|
||||
void on_actionRemove_item_triggered();
|
||||
void on_actionClear_all_triggered();
|
||||
void on_actionRemove_project_triggered();
|
||||
void on_actionClearProjects_triggered();
|
||||
|
||||
void on_tabWidget_currentChanged(int index);
|
||||
|
||||
@ -61,6 +63,8 @@ private:
|
||||
bool fillProjectsList();
|
||||
void fillIOPluginsList();
|
||||
|
||||
void updateLoadProjectButton();
|
||||
|
||||
void loadFile(const QString &filename);
|
||||
void loadProject(const QString &project);
|
||||
void loadShellcode(const QString &shellcode, const int size);
|
||||
|
@ -142,7 +142,7 @@
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
<number>2</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="filesTab">
|
||||
<attribute name="title">
|
||||
@ -379,7 +379,7 @@
|
||||
<number>5</number>
|
||||
</property>
|
||||
<item row="1" column="1">
|
||||
<widget class="QPushButton" name="selectProjectsDirButton">
|
||||
<widget class="QPushButton" name="selectProjectFileButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
@ -392,17 +392,14 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLineEdit" name="projectsDirEdit">
|
||||
<widget class="QLineEdit" name="projectFileEdit">
|
||||
<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">
|
||||
<widget class="QLabel" name="projectFileLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
@ -410,7 +407,7 @@
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string><html><head/><body><p><span style=" font-weight:600;">Projects path (dir.projects):</span></p></body></html></string>
|
||||
<string><html><head/><body><p><span style=" font-weight:600;">Open Project</span></p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -532,6 +529,11 @@
|
||||
<string>Delete project</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionClearProjects">
|
||||
<property name="text">
|
||||
<string>Clear all projects</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
@ -1,81 +0,0 @@
|
||||
|
||||
#include <QFileDialog>
|
||||
|
||||
#include "core/Cutter.h"
|
||||
#include "SaveProjectDialog.h"
|
||||
#include "ui_SaveProjectDialog.h"
|
||||
#include "common/TempConfig.h"
|
||||
#include "common/Configuration.h"
|
||||
|
||||
SaveProjectDialog::SaveProjectDialog(bool quit, QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::SaveProjectDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
CutterCore *core = Core();
|
||||
|
||||
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(Config()->getDirProjects());
|
||||
ui->simpleCheckBox->setChecked(core->getConfigb("prj.simple"));
|
||||
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()
|
||||
{
|
||||
QString currentDir = ui->projectsDirEdit->text();
|
||||
if (currentDir.startsWith("~")) {
|
||||
currentDir = QDir::homePath() + currentDir.mid(1);
|
||||
}
|
||||
|
||||
const QString& dir = QDir::toNativeSeparators(QFileDialog::getExistingDirectory(this,
|
||||
tr("Select project path (dir.projects)"),
|
||||
currentDir));
|
||||
|
||||
if (!dir.isEmpty()) {
|
||||
ui->projectsDirEdit->setText(dir);
|
||||
}
|
||||
}
|
||||
|
||||
void SaveProjectDialog::on_buttonBox_clicked(QAbstractButton *button)
|
||||
{
|
||||
if (QDialogButtonBox::DestructiveRole == ui->buttonBox->buttonRole(button)) {
|
||||
QDialog::done(QDialog::Accepted);
|
||||
}
|
||||
}
|
||||
|
||||
void SaveProjectDialog::accept()
|
||||
{
|
||||
const QString& projectName = ui->nameEdit->text().trimmed();
|
||||
if (!CutterCore::isProjectNameValid(projectName)) {
|
||||
QMessageBox::critical(this, tr("Save project"), tr("Invalid project name."));
|
||||
ui->nameEdit->setFocus();
|
||||
return;
|
||||
}
|
||||
TempConfig tempConfig;
|
||||
Config()->setDirProjects(ui->projectsDirEdit->text().toUtf8().constData());
|
||||
tempConfig.set("dir.projects", Config()->getDirProjects())
|
||||
.set("prj.simple", ui->simpleCheckBox->isChecked())
|
||||
.set("prj.files", ui->filesCheckBox->isChecked())
|
||||
.set("prj.git", ui->gitCheckBox->isChecked())
|
||||
.set("prj.zip", ui->zipCheckBox->isChecked());
|
||||
|
||||
Core()->saveProject(projectName);
|
||||
|
||||
QDialog::accept();
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
#ifndef SAVEPROJECTDIALOG_H
|
||||
#define SAVEPROJECTDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QAbstractButton>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace Ui {
|
||||
class SaveProjectDialog;
|
||||
}
|
||||
|
||||
class SaveProjectDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
explicit SaveProjectDialog(bool quit, QWidget *parent = nullptr);
|
||||
~SaveProjectDialog();
|
||||
|
||||
virtual void accept() override;
|
||||
|
||||
private slots:
|
||||
void on_buttonBox_clicked(QAbstractButton *button);
|
||||
void on_selectProjectsDirButton_clicked();
|
||||
|
||||
private:
|
||||
std::unique_ptr<Ui::SaveProjectDialog> ui;
|
||||
};
|
||||
|
||||
#endif // SAVEPROJECTDIALOG_H
|
@ -1,144 +0,0 @@
|
||||
<?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">
|
||||
<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="simpleCheckBox">
|
||||
<property name="text">
|
||||
<string>Use simple project saving style (prj.simple, recommended)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</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>
|
Loading…
Reference in New Issue
Block a user