1// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
2//
3// SPDX-License-Identifier: GPL-3.0-or-later
4
5#include "symboltreeview.h"
6#include "symbolmodel.h"
7#include "definitions.h"
8
9#include "services/project/projectservice.h"
10
11#include "symboldelegate.h"
12
13#include <QHeaderView>
14#include <QDirIterator>
15#include <QStandardItemModel>
16
17class SymbolTreeViewPrivate
18{
19 friend class SymbolTreeView;
20 SymbolTreeView *const q;
21 QModelIndex selIndex;
22 QFileSystemModel *model {nullptr};
23 SymbolDelegate *delegate;
24 QMenu *getFileLineMenu(const QString &filePath);
25 SymbolTreeViewPrivate(SymbolTreeView *qq): q(qq){}
26};
27
28SymbolTreeView::SymbolTreeView(QWidget *parent)
29 : QTreeView(parent)
30 , d (new SymbolTreeViewPrivate(this))
31{
32 d->model = new SymbolModel();
33 d->delegate = new SymbolDelegate;
34 QTreeView::setModel(d->model);
35 QTreeView::setItemDelegate(d->delegate);
36
37 setContextMenuPolicy(Qt::CustomContextMenu);
38 setEditTriggers(QTreeView::NoEditTriggers); //节点不能编辑
39 setSelectionBehavior(QTreeView::SelectRows); //一次选中整行
40 setSelectionMode(QTreeView::SingleSelection); //单选,配合上面的整行就是一次选单行
41 setFocusPolicy(Qt::NoFocus); //去掉鼠标移到节点上时的虚线框
42 header()->setVisible(false);
43 QObject::connect(this, &QTreeView::doubleClicked,
44 this, &SymbolTreeView::doDoubleClieked,
45 Qt::UniqueConnection);
46 QObject::connect(this, &QTreeView::customContextMenuRequested,
47 this, &SymbolTreeView::doContextMenu,
48 Qt::UniqueConnection);
49}
50
51SymbolTreeView::~SymbolTreeView()
52{
53 if (d)
54 delete d;
55}
56
57void SymbolTreeView::setRootPath(const QString &filePath)
58{
59 d->model->setRootPath(filePath);
60 setRootIndex(d->model->index(filePath));
61}
62
63void SymbolTreeView::doDoubleClieked(const QModelIndex &index)
64{
65 Q_UNUSED(index)
66 // nothing to do
67}
68
69void SymbolTreeView::doContextMenu(const QPoint &point)
70{
71 QModelIndex index = indexAt(point);
72 if (!index.isValid())
73 return;
74
75 setCurrentIndex(index);
76
77 QMenu *contextMenu{nullptr};
78 if (d->model->isDir(index)) {
79 QString filePath = d->model->filePath(index);
80 QDir currDir(filePath);
81 currDir.setFilter(QDir::Files|QDir::Hidden);
82 currDir.setSorting(QDir::Name);
83 QStringList files = currDir.entryList();
84 qInfo() << files;
85
86 if (files.contains(SymbolPri::definitionsFileName)
87 || files.contains(SymbolPri::declaredFileName)) {
88 contextMenu = new QMenu(this);
89 }
90
91 if (files.contains(SymbolPri::definitionsFileName)) {
92 QAction *newAction = new QAction(SymbolPri::definitionsAcStr, contextMenu);
93 contextMenu->addAction(newAction);
94 auto defJumpMenu = d->getFileLineMenu(filePath + QDir::separator() + SymbolPri::definitionsFileName);
95 if (defJumpMenu) {
96 newAction->setMenu(defJumpMenu);
97 }
98 }
99
100 if (files.contains(SymbolPri::declaredFileName)) {
101 QAction *newAction = new QAction(SymbolPri::declaredAcStr, contextMenu);
102 contextMenu->addAction(newAction);
103 auto declJumpMenu = d->getFileLineMenu(filePath + QDir::separator() + SymbolPri::declaredFileName);
104 if (declJumpMenu) {
105 newAction->setMenu(declJumpMenu);
106 }
107 }
108 }
109
110 if (contextMenu) {
111 contextMenu->exec(QWidget::mapToGlobal(point));
112 delete contextMenu;
113 }
114}
115
116QMenu *SymbolTreeViewPrivate::getFileLineMenu(const QString &filePath)
117{
118 QFile file(filePath);
119 if (!file.open(QFile::ReadOnly)) {
120 qCritical() << file.errorString();
121 }
122 QMenu *defMenu = nullptr;
123 QStringList lines = QString(file.readAll()).split('\n');
124 for (auto line : lines) {
125 if (!line.isEmpty()) {
126 if (!defMenu) {
127 defMenu = new QMenu();
128 }
129 QAction *action = new QAction(defMenu);
130 QObject::connect(action, &QAction::triggered, [=](){
131 QStringList jumpLists = action->text().split(":");
132 if (jumpLists.size() >= 2) {
133 q->jumpToLine(jumpLists[0], jumpLists[1]);
134 }
135 });
136 action->setText(line);
137 defMenu->addAction(action);
138 }
139 }
140 file.close();
141 return defMenu;
142}
143