Add detail view

This commit is contained in:
LordGrimmauld 2024-03-12 11:48:43 +01:00
parent da50e7b8fa
commit d1c5a5641a
11 changed files with 323 additions and 137 deletions

View File

@ -46,6 +46,9 @@ set(PROJECT_SOURCES
Keys/MoveToScratchpadKeyListener.h Keys/MoveToScratchpadKeyListener.h
Keys/RestoreKeyListener.h Keys/RestoreKeyListener.h
Keys/MainWindowAwareKeyListener.h Keys/MainWindowAwareKeyListener.h
Keys/ToggleDetailsKeyListener.h
sway_bindings/SwayRecords.cpp
sway_bindings/SwayRecords.h
) )
if(${QT_VERSION_MAJOR} GREATER_EQUAL 6) if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)

View File

@ -53,7 +53,7 @@ protected:
return nullptr; return nullptr;
} }
private: protected:
MainWindow *window; MainWindow *window;
[[nodiscard]] SwayTreeModel* getModel() const { [[nodiscard]] SwayTreeModel* getModel() const {

View File

@ -85,7 +85,7 @@ public:
} }
std::string getKeyText() override { std::string getKeyText() override {
return "ENTER"; return "Enter";
} }
[[nodiscard]] bool canAcceptKey(int key) const override { [[nodiscard]] bool canAcceptKey(int key) const override {

View File

@ -0,0 +1,34 @@
//
// Created by grimmauld on 12.03.24.
//
#ifndef SWAYMUX_TOGGLEDETAILSKEYLISTENER_H
#define SWAYMUX_TOGGLEDETAILSKEYLISTENER_H
#include "MainWindowAwareKeyListener.h"
class ToggleDetailsKeyListener : public MainWindowAwareKeyListener {
public:
explicit ToggleDetailsKeyListener(MainWindow *pWindow) : MainWindowAwareKeyListener(pWindow) {}
void handleKeyEvent(const QKeyEvent *keyEvent) const override {
if (window->ui->windowDetails->isHidden())
window->ui->windowDetails->show();
else
window->ui->windowDetails->hide();
}
std::string getDescription() override {
return "toggle window detail view";
}
std::string getKeyText() override {
return "Tab";
}
[[nodiscard]] bool canAcceptKey(int key) const override {
return key == Qt::Key_Tab;
}
};
#endif //SWAYMUX_TOGGLEDETAILSKEYLISTENER_H

View File

@ -11,6 +11,7 @@
#include "Keys/CloseKeyListener.h" #include "Keys/CloseKeyListener.h"
#include "Keys/MoveToScratchpadKeyListener.h" #include "Keys/MoveToScratchpadKeyListener.h"
#include "Keys/RestoreKeyListener.h" #include "Keys/RestoreKeyListener.h"
#include "Keys/ToggleDetailsKeyListener.h"
#include <QTimer> #include <QTimer>
#include <iostream> #include <iostream>
@ -34,6 +35,7 @@ MainWindow::MainWindow(QWidget *parent)
swayTreeKeyHandler->addListener(new CloseKeyListener(this)); swayTreeKeyHandler->addListener(new CloseKeyListener(this));
swayTreeKeyHandler->addListener(new MoveToScratchpadKeyListener(this)); swayTreeKeyHandler->addListener(new MoveToScratchpadKeyListener(this));
swayTreeKeyHandler->addListener(new RestoreKeyListener(this)); swayTreeKeyHandler->addListener(new RestoreKeyListener(this));
swayTreeKeyHandler->addListener(new ToggleDetailsKeyListener(this));
closeHelpKeyHandler = new KeyHandler(ui->tree_page); closeHelpKeyHandler = new KeyHandler(ui->tree_page);
closeHelpKeyHandler->addListener(new CloseHelpKeyListener(ui->tree_page)); closeHelpKeyHandler->addListener(new CloseHelpKeyListener(ui->tree_page));
@ -44,6 +46,12 @@ MainWindow::MainWindow(QWidget *parent)
ui->tableView->setModel(swayTreeKeyHandler); ui->tableView->setModel(swayTreeKeyHandler);
ui->tableView->resizeColumnsToContents(); ui->tableView->resizeColumnsToContents();
ui->tableView->installEventFilter(closeHelpKeyHandler); ui->tableView->installEventFilter(closeHelpKeyHandler);
ui->windowDetails->hide();
selChanged();
connect( ui->treeView->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)),
this, SLOT(selChanged()), Qt::DirectConnection ) ;
} }
MainWindow::~MainWindow() { MainWindow::~MainWindow() {
@ -54,6 +62,7 @@ MainWindow::~MainWindow() {
} }
void MainWindow::updateModel() const { void MainWindow::updateModel() const {
ui->windowDetails->setModel(nullptr);
ui->treeView->setModel(nullptr); ui->treeView->setModel(nullptr);
auto *focused = model->getRoot() == nullptr ? nullptr : model->getRoot()->findFocused(); auto *focused = model->getRoot() == nullptr ? nullptr : model->getRoot()->findFocused();
int id; int id;
@ -74,4 +83,15 @@ void MainWindow::updateModel() const {
ui->treeView->selectionModel()->setCurrentIndex(model->findIndexByNode(focused), QItemSelectionModel::ClearAndSelect); ui->treeView->selectionModel()->setCurrentIndex(model->findIndexByNode(focused), QItemSelectionModel::ClearAndSelect);
for (int c = 0; c < model->columnCount(); ++c) for (int c = 0; c < model->columnCount(); ++c)
ui->treeView->resizeColumnToContents(c); ui->treeView->resizeColumnToContents(c);
selChanged();
} }
void MainWindow::selChanged() const {
auto current = ui->treeView->selectionModel()->currentIndex();
auto *selected = model->getSelectedNode(current);
ui->windowDetails->setModel(nullptr);
ui->windowDetails->setModel(&selected->node);
ui->windowDetails->resizeColumnsToContents();
ui->windowDetails->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft);
}

View File

@ -23,9 +23,9 @@ public:
SwayTreeModel* model; SwayTreeModel* model;
Ui::MainWindow *ui; Ui::MainWindow *ui;
public slots:
void selChanged() const;
private: private:
// QTimer* modelUpdateTimer{};
KeyHandler* swayTreeKeyHandler; KeyHandler* swayTreeKeyHandler;
KeyHandler* closeHelpKeyHandler; KeyHandler* closeHelpKeyHandler;
}; };

View File

@ -26,6 +26,11 @@
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="font">
<font>
<pointsize>20</pointsize>
</font>
</property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<item row="0" column="0"> <item row="0" column="0">
<widget class="QStackedWidget" name="stackedWidget"> <widget class="QStackedWidget" name="stackedWidget">
@ -41,13 +46,10 @@
</property> </property>
<layout class="QGridLayout" name="gridLayoutTree"> <layout class="QGridLayout" name="gridLayoutTree">
<item row="0" column="0"> <item row="0" column="0">
<widget class="QTreeView" name="treeView"> <widget class="QTreeView" name="treeView"/>
<property name="font"> </item>
<font> <item row="0" column="1">
<pointsize>20</pointsize> <widget class="QTableView" name="windowDetails"/>
</font>
</property>
</widget>
</item> </item>
</layout> </layout>
</widget> </widget>
@ -59,14 +61,8 @@
</sizepolicy> </sizepolicy>
</property> </property>
<layout class="QGridLayout" name="gridLayoutKeys"> <layout class="QGridLayout" name="gridLayoutKeys">
<item row="0" column="0"> <item row="2" column="0">
<widget class="QTableView" name="tableView"> <widget class="QTableView" name="tableView"/>
<property name="font">
<font>
<pointsize>20</pointsize>
</font>
</property>
</widget>
</item> </item>
</layout> </layout>
</widget> </widget>

View File

@ -0,0 +1,23 @@
//
// Created by grimmauld on 12.03.24.
//
#include "SwayRecords.h"
QVariant SwayRecord::data(const QModelIndex &index, int role) const {
if (!index.isValid() || role != Qt::DisplayRole)
return {};
switch (index.column()) {
case 0:
return QString::fromStdString(jsonFields[index.row()].first);
case 1:
return QString::fromStdString(jsonFields[index.row()].second);
default:
return {};
}
}
bool SwayRecord::shouldIgnoreKey(const std::string &key) {
return key == "floating_nodes" || key == "nodes";
}

224
sway_bindings/SwayRecords.h Normal file
View File

@ -0,0 +1,224 @@
//
// Created by grimmauld on 12.03.24.
//
#ifndef SWAYMUX_SWAYRECORDS_H
#define SWAYMUX_SWAYRECORDS_H
#include <nlohmann/json.hpp>
#include <QAbstractTableModel>
#include <unordered_map>
#include <unordered_set>
using json = nlohmann::json;
#include "Sway.h"
namespace NodeType {
enum NodeType {
root, output, workspace, con, floating_con
};
static NodeType fromString(const std::string &str) {
if (str == "output") {
return output;
}
if (str == "workspace") {
return workspace;
}
if (str == "con") {
return con;
}
if (str == "floating_con") {
return floating_con;
}
return root;
}
static std::string toString(NodeType nodeType) {
switch (nodeType) {
case output:
return "output";
case workspace:
return "workspace";
case con:
return "con";
case floating_con:
return "floating_con";
default:
return "root";
}
}
static QString toQString(NodeType nodeType) {
return QString::fromStdString(toString(nodeType));
}
}
namespace NodeLayout {
enum NodeLayout {
splith, splitv, stacked, tabbed, output
};
static NodeLayout fromString(const std::string &str) {
if (str == "splith") {
return splith;
}
if (str == "splitv") {
return splitv;
}
if (str == "stacked") {
return stacked;
}
if (str == "tabbed") {
return tabbed;
}
return output;
}
static std::string toString(NodeLayout nodeLayout) {
switch (nodeLayout) {
case splith:
return "splith";
case splitv:
return "splitv";
case stacked:
return "stacked";
case tabbed:
return "tabbed";
default:
return "output";
}
}
static QString toQString(NodeLayout nodeLayout) {
return QString::fromStdString(toString(nodeLayout));
}
}
namespace NodeOrientation {
enum NodeOrientation {
vertical, horizontal, none
};
static NodeOrientation fromString(const std::string &str) {
if (str == "vertical") {
return vertical;
}
if (str == "horizontal") {
return horizontal;
}
return none;
}
static std::string toString(NodeOrientation nodeOrientation) {
switch (nodeOrientation) {
case vertical:
return "vertical";
case horizontal:
return "horizontal";
default:
return "none";
}
}
static QString toQString(NodeOrientation nodeOrientation) {
return QString::fromStdString(toString(nodeOrientation));
}
}
struct SwayRecord : public QAbstractTableModel {
explicit SwayRecord() :
id(0),
name("rootItem"),
type(NodeType::root),
current_border_width(0),
layout(NodeLayout::output),
orientation(NodeOrientation::none),
urgent(false),
sticky(false),
focused(false),
QAbstractTableModel(nullptr){}
[[nodiscard]] static bool shouldIgnoreKey(const std::string &key);
explicit SwayRecord(const json &rep) :
id(rep["id"]),
name(getName(rep)),
type(NodeType::fromString(rep["type"])),
border(rep["border"]),
current_border_width(rep["current_border_width"]),
layout(NodeLayout::fromString((rep["layout"]))),
orientation(NodeOrientation::fromString(rep["orientation"])),
urgent(rep["urgent"]),
sticky(rep["sticky"]),
focused(rep["focused"]),
QAbstractTableModel(nullptr) {
for (json::const_iterator it = rep.cbegin(); it != rep.cend(); ++it) {
if (!SwayRecord::shouldIgnoreKey(it.key()))
jsonFields.emplace_back(it.key(), it.value().dump());
}
};
const int id;
const std::string name;
const NodeType::NodeType type;
const std::string border;
const int current_border_width;
const NodeLayout::NodeLayout layout;
const NodeOrientation::NodeOrientation orientation;
const bool urgent;
const bool sticky;
bool focused;
[[nodiscard]] bool operator<(const SwayRecord &other) const {
return this->id < other.id;
}
[[nodiscard]] bool operator==(const SwayRecord &other) const {
return this->id == other.id;
}
[[nodiscard]] int rowCount(const QModelIndex &parent) const override {
return (int) jsonFields.size();
}
[[nodiscard]] int columnCount(const QModelIndex &parent) const override {
return 2;
}
[[nodiscard]] QVariant data(const QModelIndex &index, int role) const override;
[[nodiscard]] QVariant headerData(int section, Qt::Orientation qtOrientation,
int role) const override {
if (qtOrientation != Qt::Horizontal || role != Qt::DisplayRole)
return QVariant{};
switch (section) {
case 0:
return "Field";
case 1:
return "State";
default:
return QVariant{};
}
}
private:
std::vector<std::pair<std::string, std::string>> jsonFields;
static std::string getName(const json& rep) {
if(rep["name"].is_null())
return "Untitled Container";
std::string internal = rep["name"];
if (internal == "__i3" && NodeType::fromString(rep["type"]) == NodeType::output)
return "Virtual Display";
if (internal == "__i3_scratch" && NodeType::fromString(rep["type"]) == NodeType::workspace)
return "Scratchpad";
return internal;
}
};
#endif //SWAYMUX_SWAYRECORDS_H

View File

@ -20,7 +20,7 @@ struct swaymsg {
explicit swaymsg(const unsigned int payloadType, const char *msg, const unsigned int payload_len) explicit swaymsg(const unsigned int payloadType, const char *msg, const unsigned int payload_len)
: payload_len(payload_len), payload_type(payloadType) { : payload_len(payload_len), payload_type(payloadType) {
this->msg = static_cast<char *>(std::malloc(payload_len)); this->msg = new char[payload_len];
std::memcpy(this->msg, msg, payload_len); std::memcpy(this->msg, msg, payload_len);
buff = new unsigned char [size()]; buff = new unsigned char [size()];

View File

@ -9,124 +9,11 @@
#include <utility> #include <utility>
#include <iostream> #include <iostream>
using json = nlohmann::json; using json = nlohmann::json;
#include "../sway_bindings/SwayRecords.h"
#include "AbstractTreeNode.h" #include "AbstractTreeNode.h"
#include "../sway_bindings/Sway.h"
namespace NodeType {
enum NodeType {
root, output, workspace, con, floating_con
};
static NodeType fromString(const std::string &str) {
if (str == "output") {
return output;
}
if (str == "workspace") {
return workspace;
}
if (str == "con") {
return con;
}
if (str == "floating_con") {
return floating_con;
}
return root;
}
}
namespace NodeLayout {
enum NodeLayout {
splith, splitv, stacked, tabbed, output
};
static NodeLayout fromString(const std::string &str) {
if (str == "splith") {
return splith;
}
if (str == "splitv") {
return splitv;
}
if (str == "stacked") {
return stacked;
}
if (str == "tabbed") {
return tabbed;
}
return output;
}
}
namespace NodeOrientation {
enum NodeOrientation {
vertical, horizontal, none
};
static NodeOrientation fromString(const std::string &str) {
if (str == "vertical") {
return vertical;
}
if (str == "horizontal") {
return horizontal;
}
return none;
}
}
struct SwayRecord {
explicit SwayRecord() :
id(0),
name("rootItem"),
type(NodeType::root),
current_border_width(0),
layout(NodeLayout::output),
orientation(NodeOrientation::none),
urgent(false),
sticky(false),
focused(false) {}
explicit SwayRecord(const json &rep) :
id(rep["id"]),
name(getName(rep)),
type(NodeType::fromString(rep["type"])),
border(rep["border"]),
current_border_width(rep["current_border_width"]),
layout(NodeLayout::fromString((rep["layout"]))),
orientation(NodeOrientation::fromString(rep["orientation"])),
urgent(rep["urgent"]),
sticky(rep["sticky"]),
focused(rep["focused"]) {};
const int id;
const std::string name;
const NodeType::NodeType type;
const std::string border;
const int current_border_width;
const NodeLayout::NodeLayout layout;
const NodeOrientation::NodeOrientation orientation;
const bool urgent;
const bool sticky;
bool focused;
[[nodiscard]] bool operator<(const SwayRecord &other) const {
return this->id < other.id;
}
[[nodiscard]] bool operator==(const SwayRecord &other) const {
return this->id == other.id;
}
private:
static std::string getName(const json& rep) {
if(rep["name"].is_null())
return "Untitled Container";
std::string internal = rep["name"];
if (internal == "__i3" && NodeType::fromString(rep["type"]) == NodeType::output)
return "Virtual Display";
if (internal == "__i3_scratch" && NodeType::fromString(rep["type"]) == NodeType::workspace)
return "Scratchpad";
return internal;
}
};
class SwayTreeNode : public AbstractTreeNode<SwayTreeNode> { class SwayTreeNode : public AbstractTreeNode<SwayTreeNode> {
public: public:
@ -151,8 +38,7 @@ public:
explicit SwayTreeNode(SwayTreeNode *parent = nullptr) : node(SwayRecord()), AbstractTreeNode(parent) {}; explicit SwayTreeNode(SwayTreeNode *parent = nullptr) : node(SwayRecord()), AbstractTreeNode(parent) {};
explicit SwayTreeNode(SwayRecord node, SwayTreeNode *parent = nullptr) : node(std::move(node)), // explicit SwayTreeNode(SwayRecord node, SwayTreeNode *parent = nullptr) : node(std::move(node)), AbstractTreeNode(parent) {};
AbstractTreeNode(parent) {};
[[nodiscard]] bool operator<(const SwayTreeNode &other) const { [[nodiscard]] bool operator<(const SwayTreeNode &other) const {
return this->node < other.node; return this->node < other.node;