Skip to content

Commit

Permalink
Added project explorer tree with multi-project support.
Browse files Browse the repository at this point in the history
  • Loading branch information
vaibhavpandeyvpz committed Mar 7, 2019
1 parent a8aa91f commit cf3631a
Show file tree
Hide file tree
Showing 3 changed files with 157 additions and 21 deletions.
1 change: 0 additions & 1 deletion sources/apkdecompiledialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ QLayout *ApkDecompileDialog::buildForm(const QString &apk)
return layout;
}


QString ApkDecompileDialog::folder() const
{
return m_EditFolder->text();
Expand Down
143 changes: 123 additions & 20 deletions sources/mainwindow.cpp
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
#include <QCloseEvent>
#include <QDebug>
#include <QDesktopServices>
#include <QDockWidget>
#include <QFileDialog>
#include <QFrame>
#include <QHeaderView>
#include <QMenuBar>
#include <QMessageBox>
#include <QSettings>
#include <QStatusBar>
#include <QThread>
#include <QToolBar>
#include <QTreeWidgetItem>
#include <QUrl>
#include "apkdecompiledialog.h"
#include "apkdecompileworker.h"
Expand All @@ -27,7 +30,9 @@
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
addDockWidget(Qt::LeftDockWidgetArea, buildProjectsDock());
addToolBar(Qt::LeftToolBarArea, buildMainToolBar());
setCentralWidget(buildCentralWidget());
setMenuBar(buildMenuBar());
setMinimumSize(WINDOW_WIDTH, WINDOW_HEIGHT);
setStatusBar(buildStatusBar());
Expand All @@ -47,18 +52,35 @@ MainWindow::MainWindow(QWidget *parent)
thread->start();
}

QWidget *MainWindow::buildCentralWidget()
{
m_CentralStack = new QStackedWidget(this);
auto empty = new QLabel(m_CentralStack);
empty->setAlignment(Qt::AlignCenter);
empty->setMargin(32);
empty->setStyleSheet("QLabel { color: rgba(0, 0, 0, 25%) }");
empty->setText(tr("<h1>%1</h1><p>%2</p>")
.arg("No files open.")
.arg("You need to decompile an APK first or open an already decompiled folder. Once done, click on any file in the tree on the left top view or edit it."));
empty->setWordWrap(true);
m_CentralStack->addWidget(empty);
return m_CentralStack;
}

QToolBar *MainWindow::buildMainToolBar()
{
auto toolbar = new QToolBar(this);
toolbar->addAction(QIcon(":/icons/icons8/icons8-android-os-48.png"), tr("Open > APK"), this, &MainWindow::handleActionApk);
toolbar->addAction(QIcon(":/icons/icons8/icons8-folder-48.png"), tr("Open > Folder"), this, &MainWindow::handleActionFolder);
toolbar->addAction(QIcon(":/icons/icons8/icons8-android-os-48.png"), tr("Open APK"), this, &MainWindow::handleActionApk);
toolbar->addAction(QIcon(":/icons/icons8/icons8-folder-48.png"), tr("Open Folder"), this, &MainWindow::handleActionFolder);
toolbar->addSeparator();
toolbar->addAction(QIcon(":/icons/icons8/icons8-gear-48.png"), tr("Settings"), this, &MainWindow::handleActionSettings);
auto empty = new QWidget(this);
empty->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
toolbar->addWidget(empty);
toolbar->addAction(QIcon(":/icons/icons8/icons8-hammer-48.png"), tr("Project > Build"), this, &MainWindow::handleActionBuild);
toolbar->addAction(QIcon(":/icons/icons8/icons8-software-installer-48.png"), tr("Project > Install"), this, &MainWindow::handleActionInstall);
m_ActionBuild2 = toolbar->addAction(QIcon(":/icons/icons8/icons8-hammer-48.png"), tr("Project Build"), this, &MainWindow::handleActionBuild);
m_ActionBuild2->setEnabled(false);
m_ActionInstall2 = toolbar->addAction(QIcon(":/icons/icons8/icons8-software-installer-48.png"), tr("Project Install"), this, &MainWindow::handleActionInstall);
m_ActionInstall2->setEnabled(false);
toolbar->setIconSize(QSize(48, 48));
toolbar->setMovable(false);
return toolbar;
Expand All @@ -74,31 +96,46 @@ QMenuBar *MainWindow::buildMenuBar()
open->addSeparator();
open->addAction(tr("File"), this, &MainWindow::handleActionFile);
file->addSeparator();
file->addAction(tr("Close"), this, &MainWindow::handleActionClose, QKeySequence::Close);
file->addAction(tr("Close All"), this, &MainWindow::handleActionCloseAll);
m_ActionClose = file->addAction(tr("Close"), this, &MainWindow::handleActionClose, QKeySequence::Close);
m_ActionClose->setEnabled(false);
m_ActionCloseAll = file->addAction(tr("Close All"), this, &MainWindow::handleActionCloseAll);
m_ActionCloseAll->setEnabled(false);
file->addSeparator();
file->addAction(tr("Save"), this, &MainWindow::handleActionSave, QKeySequence::Save);
file->addAction(tr("Save All"), this, &MainWindow::handleActionSaveAll);
m_ActionSave = file->addAction(tr("Save"), this, &MainWindow::handleActionSave, QKeySequence::Save);
m_ActionSave->setEnabled(false);
m_ActionSaveAll = file->addAction(tr("Save All"), this, &MainWindow::handleActionSaveAll);
m_ActionSaveAll->setEnabled(false);
file->addSeparator();
file->addAction(tr("Quit"), this, &MainWindow::handleActionQuit, QKeySequence::Quit);
auto edit = menubar->addMenu(tr("Edit"));
edit->addAction(tr("Undo"), this, &MainWindow::handleActionUndo, QKeySequence::Undo);
edit->addAction(tr("Redo"), this, &MainWindow::handleActionRedo, QKeySequence::Redo);
m_ActionUndo = edit->addAction(tr("Undo"), this, &MainWindow::handleActionUndo, QKeySequence::Undo);
m_ActionUndo->setEnabled(false);
m_ActionRedo = edit->addAction(tr("Redo"), this, &MainWindow::handleActionRedo, QKeySequence::Redo);
m_ActionRedo->setEnabled(false);
edit->addSeparator();
edit->addAction(tr("Cut"), this, &MainWindow::handleActionCut, QKeySequence::Cut);
edit->addAction(tr("Copy"), this, &MainWindow::handleActionCopy, QKeySequence::Copy);
edit->addAction(tr("Paste"), this, &MainWindow::handleActionPaste, QKeySequence::Paste);
m_ActionCut = edit->addAction(tr("Cut"), this, &MainWindow::handleActionCut, QKeySequence::Cut);
m_ActionCut->setEnabled(false);
m_ActionCopy = edit->addAction(tr("Copy"), this, &MainWindow::handleActionCopy, QKeySequence::Copy);
m_ActionCopy->setEnabled(false);
m_ActionPaste = edit->addAction(tr("Paste"), this, &MainWindow::handleActionPaste, QKeySequence::Paste);
m_ActionPaste->setEnabled(false);
edit->addSeparator();
edit->addAction(tr("Find"), this, &MainWindow::handleActionFind, QKeySequence::Find);
edit->addAction(tr("Replace"), this, &MainWindow::handleActionReplace, QKeySequence::Replace);
edit->addAction(tr("Goto"), this, &MainWindow::handleActionGoto);
m_ActionFind = edit->addAction(tr("Find"), this, &MainWindow::handleActionFind, QKeySequence::Find);
m_ActionFind->setEnabled(false);
m_ActionReplace = edit->addAction(tr("Replace"), this, &MainWindow::handleActionReplace, QKeySequence::Replace);
m_ActionReplace->setEnabled(false);
m_ActionGoto = edit->addAction(tr("Goto"), this, &MainWindow::handleActionGoto);
m_ActionGoto->setEnabled(false);
edit->addSeparator();
edit->addAction(tr("Settings"), this, &MainWindow::handleActionSettings, QKeySequence::Preferences);
auto project = menubar->addMenu(tr("Project"));
project->addAction(tr("Build"), this, &MainWindow::handleActionBuild);
m_ActionBuild1 = project->addAction(tr("Build"), this, &MainWindow::handleActionBuild);
m_ActionBuild1->setEnabled(false);
project->addSeparator();
project->addAction(tr("Sign/Export"), this, &MainWindow::handleActionSignExport);
project->addAction(tr("Install"), this, &MainWindow::handleActionInstall);
m_ActionSign = project->addAction(tr("Sign/Export"), this, &MainWindow::handleActionSignExport);
m_ActionSign->setEnabled(false);
m_ActionInstall1 = project->addAction(tr("Install"), this, &MainWindow::handleActionInstall);
m_ActionInstall1->setEnabled(false);
auto help = menubar->addMenu(tr("Help"));
help->addAction(tr("About"), this, &MainWindow::handleActionAbout);
help->addAction(tr("Documentation"), this, &MainWindow::handleActionDocumentation);
Expand All @@ -110,6 +147,23 @@ QMenuBar *MainWindow::buildMenuBar()
return menubar;
}

QDockWidget *MainWindow::buildProjectsDock()
{
auto dock = new QDockWidget(tr("Projects"), this);
m_ProjectsTree = new QTreeWidget(this);
m_ProjectsTree->header()->hide();
m_ProjectsTree->setContextMenuPolicy(Qt::CustomContextMenu);
m_ProjectsTree->setEditTriggers(QAbstractItemView::NoEditTriggers);
m_ProjectsTree->setMinimumWidth(240);
m_ProjectsTree->setSelectionBehavior(QAbstractItemView::SelectItems);
m_ProjectsTree->setSelectionMode(QAbstractItemView::SingleSelection);
m_ProjectsTree->setSortingEnabled(false);
connect(m_ProjectsTree, &QTreeWidget::doubleClicked, this, &MainWindow::handleTreeDoubleClicked);
dock->setObjectName("ProjectsDock");
dock->setWidget(m_ProjectsTree);
return dock;
}

QStatusBar *MainWindow::buildStatusBar()
{
auto buildSeparator = [=] {
Expand Down Expand Up @@ -307,10 +361,20 @@ void MainWindow::handleDecompileFailed(const QString &apk)
void MainWindow::handleDecompileFinished(const QString &apk, const QString &folder)
{
Q_UNUSED(apk)
Q_UNUSED(folder)
m_ProgressDialog->close();
m_ProgressDialog->deleteLater();
m_StatusMessage->setText(tr("Decompilation finished."));
QFileInfo info(folder);
QTreeWidgetItem *item = new QTreeWidgetItem(m_ProjectsTree);
item->setData(0, Qt::UserRole + 1, Project);
item->setData(0, Qt::UserRole + 2, folder);
item->setIcon(0, m_FileIconProvider.icon(info));
item->setText(0, info.fileName());
reloadChildren(item);
m_ProjectsTree->addTopLevelItem(item);
m_ProjectsTree->expandItem(item);
m_ActionBuild1->setEnabled(true);
m_ActionBuild2->setEnabled(true);
}

void MainWindow::handleDecompileProgress(const int percent, const QString &message)
Expand All @@ -319,6 +383,23 @@ void MainWindow::handleDecompileProgress(const int percent, const QString &messa
m_ProgressDialog->setValue(percent);
}

void MainWindow::handleTreeDoubleClicked(const QModelIndex &index)
{
const int type = index.data(Qt::UserRole + 1).toInt();
const QString path = index.data(Qt::UserRole + 2).toString();
#ifdef QT_DEBUG
qDebug() << "User double clicked" << path;
#endif
switch (type) {
case Project:
break;
case Folder:
break;
case File:
break;
}
}

void MainWindow::handleVersionResolved(const QString &binary, const QString &version)
{
#ifdef QT_DEBUG
Expand All @@ -337,6 +418,28 @@ void MainWindow::handleVersionResolved(const QString &binary, const QString &ver
}
}

void MainWindow::reloadChildren(QTreeWidgetItem *item)
{
while (item->childCount()) {
qDeleteAll(item->takeChildren());
}
QDir dir(item->data(0, Qt::UserRole + 2).toString());
if (dir.exists()) {
QFileInfoList files = dir.entryInfoList(QDir::AllEntries | QDir::NoDotAndDotDot, QDir::DirsFirst);
foreach (QFileInfo info, files) {
QTreeWidgetItem *child = new QTreeWidgetItem(item);
child->setData(0, Qt::UserRole + 1, info.isDir() ? Folder : File);
child->setData(0, Qt::UserRole + 2, info.absoluteFilePath());
child->setIcon(0, m_FileIconProvider.icon(info));
child->setText(0, info.fileName());
item->addChild(child);
if (info.isDir()) {
reloadChildren(child);
}
}
}
}

MainWindow::~MainWindow()
{
}
34 changes: 34 additions & 0 deletions sources/mainwindow.h
Original file line number Diff line number Diff line change
@@ -1,29 +1,59 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QFileIconProvider>
#include <QLabel>
#include <QMainWindow>
#include <QMap>
#include <QProgressDialog>
#include <QStackedWidget>
#include <QTreeWidget>

class MainWindow : public QMainWindow
{
Q_OBJECT
public:
enum TreeItemType {
Project = 0,
Folder,
File
};
MainWindow(QWidget *parent = nullptr);
~MainWindow();
protected:
void closeEvent(QCloseEvent *event);
private:
QAction *m_ActionBuild1;
QAction *m_ActionBuild2;
QAction *m_ActionClose;
QAction *m_ActionCloseAll;
QAction *m_ActionCopy;
QAction *m_ActionCut;
QAction *m_ActionFind;
QAction *m_ActionGoto;
QAction *m_ActionInstall1;
QAction *m_ActionInstall2;
QAction *m_ActionPaste;
QAction *m_ActionRedo;
QAction *m_ActionReplace;
QAction *m_ActionSave;
QAction *m_ActionSaveAll;
QAction *m_ActionSign;
QAction *m_ActionUndo;
QStackedWidget *m_CentralStack;
QFileIconProvider m_FileIconProvider;
QProgressDialog *m_ProgressDialog;
QTreeWidget *m_ProjectsTree;
QLabel *m_StatusMessage;
QLabel *m_VersionAdb;
QLabel *m_VersionApktool;
QLabel *m_VersionJadx;
QLabel *m_VersionJava;
QLabel *m_VersionUberApkSigner;
QWidget *buildCentralWidget();
QToolBar *buildMainToolBar();
QMenuBar *buildMenuBar();
QDockWidget *buildProjectsDock();
QStatusBar *buildStatusBar();
private slots:
void handleActionAbout();
Expand Down Expand Up @@ -54,7 +84,11 @@ private slots:
void handleDecompileFailed(const QString &apk);
void handleDecompileFinished(const QString &apk, const QString &folder);
void handleDecompileProgress(const int percent, const QString &message);
void handleTreeDoubleClicked(const QModelIndex &index);
void handleVersionResolved(const QString &binary, const QString &version);
void reloadChildren(QTreeWidgetItem *item);
};

Q_DECLARE_METATYPE(MainWindow::TreeItemType);

#endif // MAINWINDOW_H

0 comments on commit cf3631a

Please sign in to comment.