1// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
2//
3// SPDX-License-Identifier: GPL-3.0-or-later
4
5#include "texteditsplitter.h"
6#include "transceiver/codeeditorreceiver.h"
7
8#include <QBoxLayout>
9#include <QDebug>
10
11namespace Private {
12static TextEditSplitter *splitter = nullptr;
13}
14
15TextEditSplitter::TextEditSplitter(QWidget *parent)
16 : QWidget (parent)
17 , vLayout(new QVBoxLayout)
18 , mainSplitter(new QSplitter)
19{
20 tabWidget = new TextEditTabWidget(mainSplitter);
21 mainSplitter->addWidget(tabWidget);
22 mainSplitter->setHandleWidth(0);
23 tabWidgets.insert(tabWidget, true);
24 splitters.insert(mainSplitter, {tabWidget, nullptr});
25 tabWidget->setCloseButtonVisible(false);
26 tabWidget->setSplitButtonVisible(false);
27
28 QObject::connect(EditorCallProxy::instance(), &EditorCallProxy::toOpenFileWithKey,
29 tabWidget, &TextEditTabWidget::openFileWithKey);
30 QObject::connect(tabWidget, &TextEditTabWidget::splitClicked,
31 this, &TextEditSplitter::doSplit);
32 QObject::connect(tabWidget, &TextEditTabWidget::closed,
33 this, &TextEditSplitter::doClose);
34 QObject::connect(tabWidget, &TextEditTabWidget::selected,
35 this, &TextEditSplitter::doSelected);
36 QObject::connect(tabWidget, &TextEditTabWidget::closeWidget,
37 this, &TextEditSplitter::doClose);
38 QObject::connect(tabWidget, &TextEditTabWidget::sigOpenFile,
39 this, &TextEditSplitter::doShowSplit);
40 QObject::connect(EditorCallProxy::instance(), &EditorCallProxy::toAddDebugPoint,
41 tabWidget, &TextEditTabWidget::addDebugPoint);
42 QObject::connect(EditorCallProxy::instance(), &EditorCallProxy::toRemoveDebugPoint,
43 tabWidget, &TextEditTabWidget::removeDebugPoint);
44
45 QHBoxLayout *hLayout = new QHBoxLayout;
46 hLayout->addStretch(20);
47
48 vLayout->addLayout(hLayout);
49 vLayout->addWidget(mainSplitter);
50 vLayout->setContentsMargins(0, 0, 0, 0);
51 this->setLayout(vLayout);
52
53}
54
55TextEditSplitter::~TextEditSplitter()
56{
57
58}
59
60void TextEditSplitter::updateClose(QSplitter *splitter, TextEditTabWidget *textEditTabWidget)
61{
62 QSplitter *parentSplitter;
63 if (splitter != mainSplitter) {
64 parentSplitter = qobject_cast<QSplitter *>(splitter->parent());
65 } else {
66 parentSplitter = mainSplitter;
67 }
68
69 if (splitters[splitter].first && splitters[splitter].second) {
70 if (splitter == mainSplitter) {
71 int index = splitter->indexOf(textEditTabWidget);
72 if (index) {
73 splitters[splitter].second = nullptr;
74 } else {
75 splitters[splitter].first = nullptr;
76 }
77 tabWidgets.remove(textEditTabWidget);
78 delete textEditTabWidget;
79 } else {
80 int parentIndex = parentSplitter->indexOf(splitter);
81 TextEditTabWidget *textEdit;
82 if (splitters[splitter].first == textEditTabWidget) {
83 textEdit = splitters[splitter].second;
84 } else {
85 textEdit = splitters[splitter].first;
86 }
87 if (parentIndex) {
88 splitters[parentSplitter].second = textEdit;
89 } else {
90 splitters[parentSplitter].first = textEdit;
91 }
92 textEdit->setParent(parentSplitter);
93 parentSplitter->insertWidget(parentIndex, textEdit);
94 tabWidgets.remove(textEditTabWidget);
95 delete textEditTabWidget;
96 splitters.remove(splitter);
97 delete splitter;
98 }
99 } else {
100 tabWidgets.remove(textEditTabWidget);
101 delete textEditTabWidget;
102 for (auto it = splitters.begin(); it != splitters.end(); ++it) {
103 if (!it->first && !it->second) {
104 splitter->setOrientation(it.key()->orientation());
105 it->first->setParent(splitter);
106 it->second->setParent(splitter);
107 splitter->insertWidget(0, it->first);
108 splitter->insertWidget(1, it->second);
109 splitters[splitter] = {it->first, it->second};
110 splitters.remove(it.key());
111 delete it.key();
112 break;
113 }
114 }
115 }
116
117 for (auto it = tabWidgets.begin(); it != tabWidgets.end(); ++it) {
118 it.key()->setSplitButtonVisible(true);
119 }
120 if (tabWidgets.size() == 1) {
121 auto it = tabWidgets.begin();
122 it.key()->setCloseButtonVisible(false);
123 }
124}
125
126void TextEditSplitter::doSplit(Qt::Orientation orientation, const newlsp::ProjectKey &key, const QString &file)
127{
128 auto oldEditWidget = qobject_cast<TextEditTabWidget*>(sender());
129 if (!oldEditWidget)
130 return;
131 auto splitter = qobject_cast<QSplitter *>(oldEditWidget->parent());
132 QSplitter *newSplitter;
133 if (tabWidgets.size() == 1) {
134 newSplitter = mainSplitter;
135 } else {
136 newSplitter = new QSplitter(splitter);
137 }
138 newSplitter->setOrientation(orientation);
139 newSplitter->setHandleWidth(0);
140 newSplitter->setOpaqueResize(true);
141 newSplitter->setChildrenCollapsible(false);
142 int index = splitter->indexOf(oldEditWidget);
143 oldEditWidget->setParent(newSplitter);
144 oldEditWidget->setCloseButtonVisible(true);
145
146 TextEditTabWidget *newEditWidget = new TextEditTabWidget(newSplitter);
147 if (oldEditWidget == splitters[splitter].first) {
148 splitters[splitter].first = nullptr;
149 } else {
150 splitters[splitter].second = nullptr;
151 }
152 splitters[newSplitter] = {oldEditWidget, newEditWidget};
153 tabWidgets.insert(newEditWidget, true);
154 tabWidgets[oldEditWidget] = false;
155 if (tabWidgets.size() >= 4) {
156 for (auto it = tabWidgets.begin(); it != tabWidgets.end(); ++it) {
157 it.key()->setSplitButtonVisible(false);
158 }
159 }
160 if (key.isValid()) {
161 newEditWidget->openFileWithKey(key, file);
162 }
163 if (tabWidgets.size() == 2) {
164 splitter->addWidget(newEditWidget);
165 } else {
166 splitter->insertWidget(index, newSplitter);
167 }
168
169 // cancel all open file sig-slot from texteditwidget
170 QObject::disconnect(EditorCallProxy::instance(), &EditorCallProxy::toOpenFileWithKey,
171 oldEditWidget, &TextEditTabWidget::openFileWithKey);
172
173 QObject::disconnect(EditorCallProxy::instance(), &EditorCallProxy::toJumpFileLineWithKey,
174 oldEditWidget, &TextEditTabWidget::jumpToLineWithKey);
175
176 QObject::disconnect(EditorCallProxy::instance(), &EditorCallProxy::toRunFileLineWithKey,
177 oldEditWidget, &TextEditTabWidget::runningToLineWithKey);
178
179 // connect new texteditwidget openfile slot
180 QObject::connect(EditorCallProxy::instance(), &EditorCallProxy::toOpenFileWithKey,
181 newEditWidget, &TextEditTabWidget::openFileWithKey);
182
183 // connect selected texteditwidget sig-slot bind, from texteditwidget focus
184 QObject::connect(newEditWidget, &TextEditTabWidget::splitClicked,
185 this, &TextEditSplitter::doSplit);
186
187 QObject::connect(newEditWidget, &TextEditTabWidget::selected,
188 this, &TextEditSplitter::doSelected);
189
190 QObject::connect(newEditWidget, &TextEditTabWidget::closed,
191 this, &TextEditSplitter::doClose);
192 QObject::connect(newEditWidget, &TextEditTabWidget::closeWidget,
193 this, &TextEditSplitter::doClose);
194 QObject::connect(newEditWidget, &TextEditTabWidget::sigOpenFile,
195 this, &TextEditSplitter::doShowSplit);
196 QObject::connect(EditorCallProxy::instance(), &EditorCallProxy::toAddDebugPoint,
197 newEditWidget, &TextEditTabWidget::addDebugPoint);
198 QObject::connect(EditorCallProxy::instance(), &EditorCallProxy::toRemoveDebugPoint,
199 newEditWidget, &TextEditTabWidget::removeDebugPoint);
200}
201
202void TextEditSplitter::doSelected(bool state)
203{
204 auto textEditTabWidget = qobject_cast<TextEditTabWidget*>(sender());
205 if (!textEditTabWidget)
206 return;
207
208 auto findIsConnEdit = [=]() -> TextEditTabWidget*
209 {
210 for(auto it = tabWidgets.begin(); it != tabWidgets.end(); ++it) {
211 if (it.value() == true)
212 return it.key();
213 }
214 return nullptr;
215 };
216
217 if (tabWidgets.values().contains(true)) {
218 if (state) {
219 while (tabWidgets.values().contains(true)) {
220 auto edit = findIsConnEdit();
221 if (edit) {
222 QObject::disconnect(EditorCallProxy::instance(), &EditorCallProxy::toOpenFileWithKey,
223 edit, &TextEditTabWidget::openFileWithKey);
224 QObject::disconnect(EditorCallProxy::instance(), &EditorCallProxy::toJumpFileLineWithKey,
225 edit, &TextEditTabWidget::jumpToLineWithKey);
226 QObject::disconnect(EditorCallProxy::instance(), &EditorCallProxy::toRunFileLineWithKey,
227 edit, &TextEditTabWidget::runningToLineWithKey);
228 QObject::disconnect(EditorCallProxy::instance(), &EditorCallProxy::toSetModifiedAutoReload,
229 edit, &TextEditTabWidget::setModifiedAutoReload);
230 tabWidgets[edit] = false;
231 }
232 }
233 QObject::connect(EditorCallProxy::instance(), &EditorCallProxy::toAddDebugPoint,
234 textEditTabWidget, &TextEditTabWidget::addDebugPoint);
235 QObject::connect(EditorCallProxy::instance(), &EditorCallProxy::toRemoveDebugPoint,
236 textEditTabWidget, &TextEditTabWidget::removeDebugPoint);
237 QObject::connect(EditorCallProxy::instance(), &EditorCallProxy::toOpenFileWithKey,
238 textEditTabWidget, &TextEditTabWidget::openFileWithKey);
239 QObject::connect(EditorCallProxy::instance(), &EditorCallProxy::toJumpFileLineWithKey,
240 textEditTabWidget, &TextEditTabWidget::jumpToLineWithKey);
241 QObject::connect(EditorCallProxy::instance(), &EditorCallProxy::toRunFileLineWithKey,
242 textEditTabWidget, &TextEditTabWidget::runningToLineWithKey);
243 QObject::connect(EditorCallProxy::instance(), &EditorCallProxy::toSetModifiedAutoReload,
244 textEditTabWidget, &TextEditTabWidget::setModifiedAutoReload);
245 tabWidgets[textEditTabWidget] = state;
246 }
247 }
248}
249
250void TextEditSplitter::doShowSplit()
251{
252 if (tabWidgets.size() > 1)
253 return;
254 auto textEditTabWidget = qobject_cast<TextEditTabWidget*>(sender());
255 textEditTabWidget->setSplitButtonVisible(true);
256}
257
258TextEditSplitter *TextEditSplitter::instance()
259{
260 if (!Private::splitter)
261 Private::splitter = new TextEditSplitter;
262 return Private::splitter;
263}
264
265void TextEditSplitter::doClose()
266{
267 auto textEditTabWidget = qobject_cast<TextEditTabWidget*>(sender());
268 if (tabWidgets.size() == 1) {
269 textEditTabWidget->setCloseButtonVisible(false);
270 textEditTabWidget->setSplitButtonVisible(false);
271 return;
272 }
273 auto splitter = qobject_cast<QSplitter *>(textEditTabWidget->parent());
274 if (tabWidgets[textEditTabWidget]) {
275 auto it = tabWidgets.begin();
276 if (it.key() == textEditTabWidget)
277 ++it;
278 it.value() = true;
279 QObject::connect(EditorCallProxy::instance(), &EditorCallProxy::toAddDebugPoint,
280 textEditTabWidget, &TextEditTabWidget::addDebugPoint);
281 QObject::connect(EditorCallProxy::instance(), &EditorCallProxy::toRemoveDebugPoint,
282 textEditTabWidget, &TextEditTabWidget::removeDebugPoint);
283 QObject::connect(EditorCallProxy::instance(), &EditorCallProxy::toOpenFileWithKey,
284 it.key(), &TextEditTabWidget::openFileWithKey);
285 QObject::connect(EditorCallProxy::instance(), &EditorCallProxy::toJumpFileLineWithKey,
286 it.key(), &TextEditTabWidget::jumpToLineWithKey);
287 QObject::connect(EditorCallProxy::instance(), &EditorCallProxy::toRunFileLineWithKey,
288 it.key(), &TextEditTabWidget::runningToLineWithKey);
289 QObject::connect(EditorCallProxy::instance(), &EditorCallProxy::toSetModifiedAutoReload,
290 it.key(), &TextEditTabWidget::setModifiedAutoReload);
291 }
292
293 updateClose(splitter, textEditTabWidget);
294}
295
296