-
Notifications
You must be signed in to change notification settings - Fork 351
/
Copy pathtxstabwidget.cpp
316 lines (290 loc) · 8.81 KB
/
txstabwidget.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
#include "txstabwidget.h"
#include "latexeditorview.h"
#include "latexdocument.h"
#include "smallUsefulFunctions.h"
TxsTabWidget::TxsTabWidget(QWidget *parent) :
QTabWidget(parent),
m_active(false)
{
setFocusPolicy(Qt::ClickFocus);
setContextMenuPolicy(Qt::PreventContextMenu);
ChangeAwareTabBar *tb = new ChangeAwareTabBar();
tb->setContextMenuPolicy(Qt::CustomContextMenu);
tb->setUsesScrollButtons(true);
//tb->setAutoHide(true);
connect(tb, SIGNAL(customContextMenuRequested(QPoint)), this, SIGNAL(tabBarContextMenuRequested(QPoint)));
connect(tb, SIGNAL(currentTabAboutToChange(int,int)), this, SLOT(currentTabAboutToChange(int,int)));
connect(tb, SIGNAL(tabLeftClicked()), this, SIGNAL(activationRequested()));
connect(tb, SIGNAL(middleMouseButtonPressed(int)), this, SLOT(onTabCloseRequest(int)));
setTabBar(tb);
setDocumentMode(true);
const QTabBar *tb2 = tabBar();
connect(tb2, SIGNAL(tabMoved(int,int)), this, SIGNAL(tabMoved(int,int)));
connect(this, SIGNAL(tabCloseRequested(int)), this, SLOT(onTabCloseRequest(int)));
setProperty("tabsClosable", true);
setProperty("movable", true);
connect(this, SIGNAL(currentChanged(int)), this, SIGNAL(currentEditorChanged()));
}
void TxsTabWidget::moveTab(int from, int to)
{
int cur = currentIndex();
QString text = tabText(from);
QWidget *wdg = widget(from);
removeTab(from);
insertTab(to, wdg, text);
if (cur == from) setCurrentIndex(to);
else if (from < to && cur >= from && cur < to)
setCurrentIndex(cur - 1);
else if (to < from && to && cur >= to && cur < from)
setCurrentIndex(cur + 1);
}
QList<LatexEditorView *> TxsTabWidget::editors() const
{
QList<LatexEditorView *> list;
for (int i = 0; i < count(); i++) {
LatexEditorView *edView = qobject_cast<LatexEditorView *>(widget(i));
Q_ASSERT(edView); // there should only be editors as tabs
list.append(edView);
}
return list;
}
bool TxsTabWidget::containsEditor(LatexEditorView *edView) const
{
if (!edView) return false;
return (indexOf(edView) >= 0);
}
LatexEditorView *TxsTabWidget::currentEditor() const
{
return qobject_cast<LatexEditorView *>(currentWidget());
}
void TxsTabWidget::setCurrentEditor(LatexEditorView *edView)
{
if (currentWidget() == edView)
return;
if (indexOf(edView) < 0) {
// catch calls in which editor is not a member tab.
// TODO: such calls are deprecated as bad practice. We should avoid them in the long run. For the moment the fallback to do nothing is ok.
qDebug() << "Warning (deprecated call): TxsTabWidget::setCurrentEditor: editor not member of TxsTabWidget" << edView;
return;
}
setCurrentWidget(edView);
}
LatexEditorView *TxsTabWidget::editorAt(QPoint p) {
int index = tabBar()->tabAt(p);
if (index < 0) return nullptr;
return qobject_cast<LatexEditorView *>(widget(index));
}
/*! \brief Mark the widget as active.
*
* If there are multiple widgets, we want to visually indicate the active one,
* i.e. the one containing the current editor.
* We currently use bold on the current tab, but due to a Qt bug we're required
* to increase the tab width all tabs in the active widget.
* see https://bugreports.qt.io/browse/QTBUG-6905
*/
void TxsTabWidget::setActive(bool active) {
if (active == m_active) return;
m_active = active;
QString baseStyle="";
if (active) {
setStyleSheet(baseStyle);// + " QTabBar {font-weight: bold;} QTabBar::tab:!selected {font-weight: normal;}");
} else {
setStyleSheet(baseStyle + " QTabBar {color: darkgrey;}");
}
if(active){
if(currentEditor())
currentEditor()->setFocus();
}
}
bool TxsTabWidget::isEmpty() const {
return (count() == 0);
}
/*!
* \brief check if active tab is the left most
* \return
*/
bool TxsTabWidget::currentEditorViewIsFirst() const {
return (currentIndex() == 0);
}
/*!
* \brief check if active tab is the right most
* \return
*/
bool TxsTabWidget::currentEditorViewIsLast() const {
return (currentIndex() >= count()-1);
}
/*!
* \brief activate tab to the right
*
* right most tab remains active, no roll over.
*/
void TxsTabWidget::gotoNextDocument()
{
if (count() <= 1) return;
int cPage = currentIndex() + 1;
if (cPage >= count()) setCurrentIndex(0);
else setCurrentIndex(cPage);
}
/*!
* \brief activate tab to the left
*
* Left most tab (0) remains active, no roll over.
*/
void TxsTabWidget::gotoPrevDocument()
{
if (count() <= 1) return;
int cPage = currentIndex() - 1;
if (cPage < 0) setCurrentIndex(count() - 1);
else setCurrentIndex(cPage);
}
/*!
* \brief activate first document/tab
*/
void TxsTabWidget::gotoFirstDocument() {
if (count() <= 1) return;
setCurrentIndex(0);
}
/*!
* \brief activate last document/tab
*/
void TxsTabWidget::gotoLastDocument() {
if (count() <= 1) return;
setCurrentIndex(count()-1);
}
void TxsTabWidget::currentTabAboutToChange(int from, int to)
{
LatexEditorView *edFrom = qobject_cast<LatexEditorView *>(widget(from));
LatexEditorView *edTo = qobject_cast<LatexEditorView *>(widget(to));
REQUIRE(edFrom);
REQUIRE(edTo);
emit editorAboutToChangeByTabClick(edFrom, edTo);
}
/*! \brief Handler for close requests coming from the tab bar.
*
* The widget cannot decide if the tab can really be closed, which can only be
* determined at top level with user interaction if there are unsaved changes to
* the editor. So we propagate the request up.
* In the long terms one might consider asking the editor instead.
*/
void TxsTabWidget::onTabCloseRequest(int i)
{
emit closeEditorRequested(editorAt(i));
}
/*!
* \brief insert tab with given editor
* \param edView editor
* \param pos position, 0 is left most
* \param asCurrent put editor as active into foreground
*/
void TxsTabWidget::insertEditor(LatexEditorView *edView, int pos, bool asCurrent)
{
Q_ASSERT(edView);
pos = insertTab(pos, edView, "?bug?");
updateTab(pos);
connectEditor(edView);
if (asCurrent) setCurrentEditor(edView);
}
/*!
* \brief remove tab which is connected to the given editor
* \param edView
*/
void TxsTabWidget::removeEditor(LatexEditorView *edView)
{
int i = indexOf(edView);
if (i >= 0)
removeTab(i);
disconnectEditor(edView);
}
/*!
* Returns the LatexEditorView at the given tab index or 0.
*/
LatexEditorView *TxsTabWidget::editorAt(int index)
{
if (index < 0 || index >= count())
return nullptr;
return qobject_cast<LatexEditorView *>(widget(index));
}
/*!
* Connect to signals of the editor so that the TabWidget will update the modified
* status and the tab text when these properties of the editor change.
*
*/
void TxsTabWidget::connectEditor(LatexEditorView *edView)
{
connect(edView->editor, SIGNAL(contentModified(bool)), this, SLOT(updateTabFromSender()));
connect(edView->editor, SIGNAL(readOnlyChanged(bool)), this, SLOT(updateTabFromSender()));
connect(edView->editor, SIGNAL(titleChanged(QString)), this, SLOT(updateTabFromSender()));
}
/*!
* Disconnect all connections from the editor to this.
*/
void TxsTabWidget::disconnectEditor(LatexEditorView *edView)
{
edView->editor->disconnect(this);
}
/*!
* Updates modified icon, tab text and tooltip.
* TODO: tooltip should be dynamically generated when required because
* this is not called always when root information changes.
*/
void TxsTabWidget::updateTab(int index)
{
//cache icons, getRealIcon is *really* slow
static QIcon readOnly = getRealIcon("document-locked");
static QIcon modified = getRealIcon("modified");
static QIcon empty = QIcon(":/images/empty.png");
LatexEditorView *edView = editorAt(index);
if (!edView) return;
// update icon
if (edView->editor->isReadOnly()) {
setTabIcon(index, readOnly);
} else if ((edView->editor->isContentModified())) {
setTabIcon(index, modified);
} else {
setTabIcon(index, empty);
}
// update tab text
setTabText(index, edView->displayNameForUI());
// update tooltip text
LatexDocument *doc = edView->document;
LatexDocument *rootDoc = doc->getRootDocument();
QString tooltip = QDir::toNativeSeparators(edView->editor->fileName());
if (doc != rootDoc) {
tooltip += tr("\nincluded document in %1").arg(rootDoc->getName());
}
setTabToolTip(index, tooltip);
}
/*!
* Helper function. This is bound to editor signals and calls updateTab() on
* the tab to which the sending editor belongs.
*/
void TxsTabWidget::updateTabFromSender()
{
QEditor *editor = qobject_cast<QEditor *>(sender());
for (int i = 0; i < count(); i++) {
if (editorAt(i)->editor == editor) {
updateTab(i);
return;
}
}
}
void ChangeAwareTabBar::mousePressEvent(QMouseEvent *event)
{
int current = currentIndex();
int toIndex = tabAt(event->pos());
if (event->button() == Qt::LeftButton) {
if (toIndex >= 0) {
emit currentTabAboutToChange(current, toIndex);
}
}
else if (event->button() == Qt::MiddleButton) {
int tabNr = tabAt(event->pos());
if (tabNr >= 0) {
emit middleMouseButtonPressed(tabNr);
}
}
QTabBar::mousePressEvent(event);
if (event->button() == Qt::LeftButton) {
emit tabLeftClicked();
}
}