Changeset View
Standalone View
src/ViewContainer.cpp
Show All 15 Lines | 1 | /* | |||
---|---|---|---|---|---|
16 | You should have received a copy of the GNU General Public License | 16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | 17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | 18 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
19 | 02110-1301 USA. | 19 | 02110-1301 USA. | ||
20 | */ | 20 | */ | ||
21 | 21 | | |||
22 | // Own | 22 | // Own | ||
23 | #include "ViewContainer.h" | 23 | #include "ViewContainer.h" | ||
24 | | ||||
25 | #include <config-konsole.h> | 24 | #include <config-konsole.h> | ||
26 | 25 | | |||
27 | // Qt | 26 | // Qt | ||
28 | #include <QStackedWidget> | 27 | #include <QTabBar> | ||
29 | #include <QToolButton> | 28 | #include <QMenu> | ||
30 | #include <QDrag> | 29 | #include <QFile> | ||
31 | #include <QDragMoveEvent> | 30 | #include <QOperatingSystemVersion> | ||
32 | #include <QMimeData> | 31 | #include <QMouseEvent> | ||
33 | #include <QHBoxLayout> | | |||
34 | #include <QVBoxLayout> | | |||
35 | 32 | | |||
36 | // KDE | 33 | // KDE | ||
37 | #include <KColorScheme> | 34 | #include <KColorScheme> | ||
38 | #include <KColorUtils> | 35 | #include <KColorUtils> | ||
39 | #include <KLocalizedString> | 36 | #include <KLocalizedString> | ||
40 | #include <KActionCollection> | 37 | #include <KActionCollection> | ||
41 | #include <QMenu> | | |||
42 | 38 | | |||
43 | // Konsole | 39 | // Konsole | ||
44 | #include "IncrementalSearchBar.h" | 40 | #include "IncrementalSearchBar.h" | ||
45 | #include "ViewProperties.h" | 41 | #include "ViewProperties.h" | ||
46 | #include "ViewContainerTabBar.h" | | |||
47 | #include "ProfileList.h" | 42 | #include "ProfileList.h" | ||
48 | #include "ViewManager.h" | 43 | #include "ViewManager.h" | ||
49 | #include "KonsoleSettings.h" | 44 | #include "KonsoleSettings.h" | ||
50 | #include "SessionController.h" | 45 | #include "SessionController.h" | ||
46 | #include "DetachableTabBar.h" | ||||
51 | 47 | | |||
52 | // TODO Perhaps move everything which is Konsole-specific into different files | 48 | // TODO Perhaps move everything which is Konsole-specific into different files | ||
53 | 49 | | |||
54 | using namespace Konsole; | 50 | using namespace Konsole; | ||
55 | 51 | | |||
56 | ViewContainer::ViewContainer(NavigationPosition position, QObject *parent) : | | |||
57 | QObject(parent), | | |||
58 | _navigationVisibility(AlwaysShowNavigation), | | |||
59 | _navigationPosition(position), | | |||
60 | _views(QList<QWidget *>()), | | |||
61 | _navigation(QHash<QWidget *, ViewProperties *>()), | | |||
62 | _features(nullptr), | | |||
63 | _searchBar(nullptr) | | |||
64 | { | | |||
65 | } | | |||
66 | | ||||
67 | ViewContainer::~ViewContainer() | | |||
68 | { | | |||
69 | foreach (QWidget *view, _views) { | | |||
70 | disconnect(view, &QWidget::destroyed, this, &Konsole::ViewContainer::viewDestroyed); | | |||
71 | } | | |||
72 | | ||||
73 | if (_searchBar != nullptr) { | | |||
74 | _searchBar->deleteLater(); | | |||
75 | } | | |||
76 | | ||||
77 | emit destroyed(this); | | |||
78 | } | | |||
79 | | ||||
80 | void ViewContainer::moveViewWidget(int, int) | | |||
81 | { | | |||
82 | } | | |||
83 | | ||||
84 | void ViewContainer::setFeatures(Features features) | | |||
85 | { | | |||
86 | _features = features; | | |||
87 | } | | |||
88 | | ||||
89 | ViewContainer::Features ViewContainer::features() const | | |||
90 | { | | |||
91 | return _features; | | |||
92 | } | | |||
93 | | ||||
94 | void ViewContainer::moveActiveView(MoveDirection direction) | | |||
95 | { | | |||
96 | const int currentIndex = _views.indexOf(activeView()); | | |||
97 | int newIndex = -1; | | |||
98 | | ||||
99 | switch (direction) { | | |||
100 | case MoveViewLeft: | | |||
101 | newIndex = qMax(currentIndex - 1, 0); | | |||
102 | break; | | |||
103 | case MoveViewRight: | | |||
104 | newIndex = qMin(currentIndex + 1, _views.count() - 1); | | |||
105 | break; | | |||
106 | } | | |||
107 | | ||||
108 | Q_ASSERT(newIndex != -1); | | |||
109 | | ||||
110 | moveViewWidget(currentIndex, newIndex); | | |||
111 | | ||||
112 | _views.swap(currentIndex, newIndex); | | |||
113 | | ||||
114 | setActiveView(_views[newIndex]); | | |||
115 | } | | |||
116 | | ||||
117 | void ViewContainer::setNavigationVisibility(NavigationVisibility mode) | | |||
118 | { | | |||
119 | _navigationVisibility = mode; | | |||
120 | navigationVisibilityChanged(mode); | | |||
121 | } | | |||
122 | | ||||
123 | ViewContainer::NavigationPosition ViewContainer::navigationPosition() const | | |||
124 | { | | |||
125 | return _navigationPosition; | | |||
126 | } | | |||
127 | | ||||
128 | void ViewContainer::setNavigationPosition(NavigationPosition position) | | |||
129 | { | | |||
130 | // assert that this position is supported | | |||
131 | Q_ASSERT(supportedNavigationPositions().contains(position)); | | |||
132 | | ||||
133 | _navigationPosition = position; | | |||
134 | | ||||
135 | navigationPositionChanged(position); | | |||
136 | } | | |||
137 | | ||||
138 | QList<ViewContainer::NavigationPosition> ViewContainer::supportedNavigationPositions() const | | |||
139 | { | | |||
140 | return QList<NavigationPosition>() << NavigationPositionTop; | | |||
141 | } | | |||
142 | | ||||
143 | void ViewContainer::setNavigationTabWidthExpanding(bool expand) | | |||
144 | { | | |||
145 | navigationTabWidthExpandingChanged(expand); | | |||
146 | } | | |||
147 | | ||||
148 | ViewContainer::NavigationVisibility ViewContainer::navigationVisibility() const | | |||
149 | { | | |||
150 | return _navigationVisibility; | | |||
151 | } | | |||
152 | | ||||
153 | void ViewContainer::setNavigationTextMode(bool mode) | | |||
154 | { | | |||
155 | navigationTextModeChanged(mode); | | |||
156 | } | | |||
157 | | ||||
158 | void ViewContainer::addView(QWidget *view, ViewProperties *item, int index) | | |||
159 | { | | |||
160 | if (index == -1) { | | |||
161 | _views.append(view); | | |||
162 | } else { | | |||
163 | _views.insert(index, view); | | |||
164 | } | | |||
165 | | ||||
166 | _navigation[view] = item; | | |||
167 | | ||||
168 | connect(view, &QWidget::destroyed, this, &Konsole::ViewContainer::viewDestroyed); | | |||
169 | | ||||
170 | addViewWidget(view, index); | | |||
171 | | ||||
172 | emit viewAdded(view, item); | | |||
173 | } | | |||
174 | | ||||
175 | void ViewContainer::viewDestroyed(QObject *view) | | |||
176 | { | | |||
177 | QWidget *widget = qobject_cast<QWidget *>(view); | | |||
178 | forgetView(widget); | | |||
179 | } | | |||
180 | | ||||
181 | void ViewContainer::forgetView(QWidget *view) | | |||
182 | { | | |||
183 | _views.removeAll(view); | | |||
184 | _navigation.remove(view); | | |||
185 | | ||||
186 | emit viewRemoved(view); | | |||
187 | | ||||
188 | if (_views.count() == 0) { | | |||
189 | emit empty(this); | | |||
190 | } | | |||
191 | } | | |||
192 | | ||||
193 | void ViewContainer::removeView(QWidget *view) | | |||
194 | { | | |||
195 | disconnect(view, &QWidget::destroyed, this, &Konsole::ViewContainer::viewDestroyed); | | |||
196 | removeViewWidget(view); | | |||
197 | forgetView(view); | | |||
198 | } | | |||
199 | | ||||
200 | const QList<QWidget *> ViewContainer::views() const | | |||
201 | { | | |||
202 | return _views; | | |||
203 | } | | |||
204 | | ||||
205 | IncrementalSearchBar *ViewContainer::searchBar() | | |||
206 | { | | |||
207 | if (_searchBar == nullptr) { | | |||
208 | _searchBar = new IncrementalSearchBar(nullptr); | | |||
209 | _searchBar->setVisible(false); | | |||
210 | connect(_searchBar, &Konsole::IncrementalSearchBar::destroyed, this, | | |||
211 | &Konsole::ViewContainer::searchBarDestroyed); | | |||
212 | } | | |||
213 | return _searchBar; | | |||
214 | } | | |||
215 | | ||||
216 | void ViewContainer::searchBarDestroyed() | | |||
217 | { | | |||
218 | _searchBar = nullptr; | | |||
219 | } | | |||
220 | | ||||
221 | void ViewContainer::activateNextView() | | |||
222 | { | | |||
223 | QWidget *active = activeView(); | | |||
224 | | ||||
225 | int index = _views.indexOf(active); | | |||
226 | | ||||
227 | if (index == -1) { | | |||
228 | return; | | |||
229 | } | | |||
230 | | ||||
231 | if (index == _views.count() - 1) { | | |||
232 | index = 0; | | |||
233 | } else { | | |||
234 | index++; | | |||
235 | } | | |||
236 | | ||||
237 | setActiveView(_views.at(index)); | | |||
238 | } | | |||
239 | | ||||
240 | void ViewContainer::activateLastView() | | |||
241 | { | | |||
242 | setActiveView(_views.at(_views.count() - 1)); | | |||
243 | } | | |||
244 | | ||||
245 | void ViewContainer::activatePreviousView() | | |||
246 | { | | |||
247 | QWidget *active = activeView(); | | |||
248 | | ||||
249 | int index = _views.indexOf(active); | | |||
250 | | ||||
251 | if (index == -1) { | | |||
252 | return; | | |||
253 | } | | |||
254 | | ||||
255 | if (index == 0) { | | |||
256 | index = _views.count() - 1; | | |||
257 | } else { | | |||
258 | index--; | | |||
259 | } | | |||
260 | | ||||
261 | setActiveView(_views.at(index)); | | |||
262 | } | | |||
263 | | ||||
264 | ViewProperties *ViewContainer::viewProperties(QWidget *view) const | | |||
265 | { | | |||
266 | Q_ASSERT(_navigation.contains(view)); | | |||
267 | | ||||
268 | return _navigation[view]; | | |||
269 | } | | |||
270 | 52 | | |||
271 | QList<QWidget *> ViewContainer::widgetsForItem(ViewProperties *item) const | 53 | TabbedViewContainer::TabbedViewContainer(ViewManager *connectedViewManager, QWidget *parent) : | ||
54 | QTabWidget(parent), | ||||
55 | _connectedViewManager(connectedViewManager), | ||||
56 | _newTabButton(new QToolButton()), | ||||
57 | _contextMenuTabIndex(-1) | ||||
272 | { | 58 | { | ||
273 | return _navigation.keys(item); | 59 | auto tabBarWidget = new DetachableTabBar(); | ||
274 | } | 60 | setTabBar(tabBarWidget); | ||
61 | setDocumentMode(true); | ||||
62 | setMovable(true); | ||||
63 | | ||||
64 | tabBar()->setContextMenuPolicy(Qt::CustomContextMenu); | ||||
65 | | ||||
66 | _newTabButton->setIcon(QIcon::fromTheme(QStringLiteral("document-new"))); | ||||
67 | _newTabButton->setAutoRaise(true); | ||||
68 | connect(_newTabButton, &QToolButton::clicked, this, [this]{ | ||||
69 | emit newViewRequest(); | ||||
70 | }); | ||||
275 | 71 | | |||
276 | TabbedViewContainer::TabbedViewContainer(NavigationPosition position, | 72 | connect(tabBar(), &QTabBar::tabCloseRequested, | ||
277 | ViewManager *connectedViewManager, QObject *parent) : | 73 | this, &TabbedViewContainer::closeTerminalTab); | ||
278 | ViewContainer(position, parent), | 74 | connect(tabBar(), &QTabBar::tabBarDoubleClicked, this, | ||
279 | _tabBar(nullptr), | | |||
280 | _stackWidget(nullptr), | | |||
281 | _containerWidget(nullptr), | | |||
282 | _connectedViewManager(connectedViewManager), | | |||
283 | _layout(nullptr), | | |||
284 | _tabBarLayout(nullptr), | | |||
285 | _newTabButton(nullptr), | | |||
sandsmark: for some reason phabricator doesn't seem to show the patch correctly, but looking at the diff… | |||||
This is probably a issue with Qt as this method is from the QTabBar. Can you show a picture as in mine it looks correct so I can see what I can do? tcanabrava: This is probably a issue with Qt as this method is from the QTabBar. Can you show a picture as… | |||||
286 | _closeTabButton(nullptr), | | |||
287 | _contextMenuTabIndex(0), | | |||
288 | _contextPopupMenu(nullptr) | | |||
289 | { | | |||
290 | _containerWidget = new QWidget; | | |||
291 | _stackWidget = new QStackedWidget(); | | |||
292 | connect(_stackWidget.data(), &QStackedWidget::widgetRemoved, this, | | |||
293 | &TabbedViewContainer::widgetRemoved); | | |||
294 | | ||||
295 | // The tab bar | | |||
296 | _tabBar = new ViewContainerTabBar(_containerWidget, this); | | |||
297 | _tabBar->setContextMenuPolicy(Qt::CustomContextMenu); | | |||
298 | _tabBar->setSupportedMimeType(ViewProperties::mimeType()); | | |||
299 | | ||||
300 | connect(_tabBar, &Konsole::ViewContainerTabBar::currentChanged, this, | | |||
301 | &Konsole::TabbedViewContainer::currentTabChanged); | | |||
302 | connect(_tabBar, &Konsole::ViewContainerTabBar::tabBarDoubleClicked, this, | | |||
303 | &Konsole::TabbedViewContainer::tabDoubleClicked); | 75 | &Konsole::TabbedViewContainer::tabDoubleClicked); | ||
304 | connect(_tabBar, &Konsole::ViewContainerTabBar::querySourceIndex, this, | 76 | connect(tabBar(), &QTabBar::customContextMenuRequested, this, | ||
305 | &Konsole::TabbedViewContainer::querySourceIndex); | | |||
306 | connect(_tabBar, &Konsole::ViewContainerTabBar::moveViewRequest, this, | | |||
307 | &Konsole::TabbedViewContainer::onMoveViewRequest); | | |||
308 | connect(_tabBar, &Konsole::ViewContainerTabBar::customContextMenuRequested, this, | | |||
309 | &Konsole::TabbedViewContainer::openTabContextMenu); | 77 | &Konsole::TabbedViewContainer::openTabContextMenu); | ||
310 | 78 | connect(tabBarWidget, &DetachableTabBar::detachTab, this, [this](int idx) { | |||
311 | connect(_tabBar, &Konsole::ViewContainerTabBar::initiateDrag, this, | 79 | emit detachTab(this, widget(idx)); | ||
312 | &Konsole::TabbedViewContainer::startTabDrag); | 80 | }); | ||
81 | connect(this, &TabbedViewContainer::currentChanged, this, [this](int index) { | ||||
82 | if (index != -1) { | ||||
83 | widget(index)->setFocus(); | ||||
84 | } | ||||
85 | }); | ||||
313 | 86 | | |||
314 | // The context menu of tab bar | 87 | // The context menu of tab bar | ||
315 | _contextPopupMenu = new QMenu(_tabBar); | 88 | _contextPopupMenu = new QMenu(tabBar()); | ||
316 | connect(_contextPopupMenu, &QMenu::aboutToHide, this, [this]() { | 89 | connect(_contextPopupMenu, &QMenu::aboutToHide, this, [this]() { | ||
317 | // Remove the read-only action when the popup closes | 90 | // Remove the read-only action when the popup closes | ||
318 | for (auto &action : _contextPopupMenu->actions()) { | 91 | for (auto &action : _contextPopupMenu->actions()) { | ||
319 | if (action->objectName() == QStringLiteral("view-readonly")) { | 92 | if (action->objectName() == QStringLiteral("view-readonly")) { | ||
320 | _contextPopupMenu->removeAction(action); | 93 | _contextPopupMenu->removeAction(action); | ||
321 | break; | 94 | break; | ||
322 | } | 95 | } | ||
323 | } | 96 | } | ||
324 | }); | 97 | }); | ||
325 | 98 | | |||
326 | #if defined(ENABLE_DETACHING) | 99 | auto detachAction = _contextPopupMenu->addAction( | ||
327 | _contextPopupMenu->addAction(QIcon::fromTheme(QStringLiteral("tab-detach")), | 100 | QIcon::fromTheme(QStringLiteral("tab-detach")), | ||
328 | i18nc("@action:inmenu", "&Detach Tab"), this, | 101 | i18nc("@action:inmenu", "&Detach Tab"), this, | ||
329 | SLOT(tabContextMenuDetachTab())); | 102 | [this] { emit detachTab(this, widget(_contextMenuTabIndex)); } | ||
330 | #endif | 103 | ); | ||
104 | detachAction->setObjectName(QStringLiteral("tab-detach")); | ||||
331 | 105 | | |||
332 | _contextPopupMenu->addAction(QIcon::fromTheme(QStringLiteral("edit-rename")), | 106 | auto editAction = _contextPopupMenu->addAction( | ||
107 | QIcon::fromTheme(QStringLiteral("edit-rename")), | ||||
333 | i18nc("@action:inmenu", "&Rename Tab..."), this, | 108 | i18nc("@action:inmenu", "&Rename Tab..."), this, | ||
334 | SLOT(tabContextMenuRenameTab())); | 109 | [this]{ renameTab(_contextMenuTabIndex); } | ||
335 | const auto contextPopupMenuActions = _contextPopupMenu->actions(); | 110 | ); | ||
336 | contextPopupMenuActions.last()->setObjectName(QStringLiteral("edit-rename")); | 111 | editAction->setObjectName(QStringLiteral("edit-rename")); | ||
337 | 112 | | |||
338 | _contextPopupMenu->addSeparator(); | 113 | auto closeAction = _contextPopupMenu->addAction( | ||
339 | 114 | QIcon::fromTheme(QStringLiteral("tab-close")), | |||
340 | _contextPopupMenu->addAction(QIcon::fromTheme(QStringLiteral("tab-close")), | 115 | i18nc("@action:inmenu", "Close Tab"), this, | ||
341 | i18nc("@action:inmenu", "&Close Tab"), this, | 116 | [this] { closeTerminalTab(_contextMenuTabIndex); } | ||
342 | SLOT(tabContextMenuCloseTab())); | 117 | ); | ||
343 | // The 'new tab' and 'close tab' button | 118 | closeAction->setVisible(!KonsoleSettings::showQuickButtons()); | ||
344 | _newTabButton = new QToolButton(_containerWidget); | 119 | closeAction->setObjectName(QStringLiteral("tab-close")); | ||
345 | _newTabButton->setFocusPolicy(Qt::NoFocus); | 120 | connect(KonsoleSettings::self(), &KonsoleSettings::configChanged, [closeAction] { | ||
346 | _newTabButton->setIcon(QIcon::fromTheme(QStringLiteral("tab-new"))); | 121 | closeAction->setVisible(!KonsoleSettings::showQuickButtons()); | ||
347 | _newTabButton->setToolTip(i18nc("@info:tooltip", "Create new tab")); | 122 | }); | ||
348 | _newTabButton->setWhatsThis(i18nc("@info:whatsthis", | | |||
349 | "Create a new tab. Press and hold to select profile from menu")); | | |||
350 | _newTabButton->adjustSize(); | | |||
351 | 123 | | |||
352 | auto profileMenu = new QMenu(_newTabButton); | 124 | auto profileMenu = new QMenu(); | ||
353 | auto profileList = new ProfileList(false, profileMenu); | 125 | auto profileList = new ProfileList(false, profileMenu); | ||
354 | profileList->syncWidgetActions(profileMenu, true); | 126 | profileList->syncWidgetActions(profileMenu, true); | ||
355 | connect(profileList, &Konsole::ProfileList::profileSelected, this, | 127 | connect(profileList, &Konsole::ProfileList::profileSelected, this, | ||
356 | static_cast<void (TabbedViewContainer::*)(Profile::Ptr)>(&Konsole::TabbedViewContainer:: | 128 | static_cast<void (TabbedViewContainer::*)(Profile::Ptr)>(&Konsole::TabbedViewContainer::newViewRequest)); | ||
357 | newViewRequest)); | 129 | // setNewViewMenu(profileMenu); | ||
358 | setNewViewMenu(profileMenu); | | |||
359 | | ||||
360 | _closeTabButton = new QToolButton(_containerWidget); | | |||
361 | _closeTabButton->setFocusPolicy(Qt::NoFocus); | | |||
362 | _closeTabButton->setIcon(QIcon::fromTheme(QStringLiteral("tab-close"))); | | |||
363 | _closeTabButton->setToolTip(i18nc("@info:tooltip", "Close tab")); | | |||
364 | _closeTabButton->setWhatsThis(i18nc("@info:whatsthis", "Close the active tab")); | | |||
365 | _closeTabButton->adjustSize(); | | |||
366 | | ||||
367 | // 'new tab' button is initially hidden. It will be shown when setFeatures() | | |||
368 | // is called with the QuickNewView flag enabled. The 'close tab' is the same. | | |||
369 | _newTabButton->setHidden(true); | | |||
370 | _closeTabButton->setHidden(true); | | |||
371 | | ||||
372 | connect(_newTabButton, &QToolButton::clicked, this, | | |||
373 | static_cast<void (TabbedViewContainer::*)()>(&Konsole::TabbedViewContainer::newViewRequest)); | | |||
374 | connect(_closeTabButton, &QToolButton::clicked, this, | | |||
375 | &Konsole::TabbedViewContainer::closeCurrentTab); | | |||
376 | 130 | | |||
377 | // Combine tab bar and 'new/close tab' buttons | 131 | konsoleConfigChanged(); | ||
378 | _tabBarLayout = new QHBoxLayout; | 132 | connect(KonsoleSettings::self(), &KonsoleSettings::configChanged, this, &TabbedViewContainer::konsoleConfigChanged); | ||
379 | _tabBarLayout->setSpacing(0); | | |||
380 | _tabBarLayout->setContentsMargins(0, 0, 0, 0); | | |||
381 | _tabBarLayout->addWidget(_newTabButton); | | |||
382 | _tabBarLayout->addWidget(_tabBar); | | |||
383 | _tabBarLayout->addWidget(_closeTabButton); | | |||
384 | | ||||
385 | // The search bar | | |||
386 | searchBar()->setParent(_containerWidget); | | |||
387 | | ||||
388 | // The overall layout | | |||
389 | _layout = new QVBoxLayout; | | |||
390 | _layout->setSpacing(0); | | |||
391 | _layout->setContentsMargins(0, 0, 0, 0); | | |||
392 | | ||||
393 | setNavigationPosition(position); | | |||
394 | | ||||
395 | _containerWidget->setLayout(_layout); | | |||
396 | } | 133 | } | ||
397 | 134 | | |||
398 | void TabbedViewContainer::setNewViewMenu(QMenu *menu) | 135 | TabbedViewContainer::~TabbedViewContainer() | ||
399 | { | 136 | { | ||
400 | _newTabButton->setMenu(menu); | 137 | for(int i = 0, end = count(); i < end; i++) { | ||
138 | auto view = widget(i); | ||||
139 | disconnect(view, &QWidget::destroyed, this, &Konsole::TabbedViewContainer::viewDestroyed); | ||||
401 | } | 140 | } | ||
402 | 141 | | |||
403 | ViewContainer::Features TabbedViewContainer::supportedFeatures() const | 142 | emit destroyed(this); | ||
404 | { | | |||
405 | return QuickNewView | QuickCloseView; | | |||
406 | } | 143 | } | ||
407 | 144 | | |||
408 | void TabbedViewContainer::setFeatures(Features features) | 145 | void TabbedViewContainer::konsoleConfigChanged() | ||
409 | { | 146 | { | ||
410 | ViewContainer::setFeatures(features); | 147 | setTabBarAutoHide((bool) KonsoleSettings::tabBarVisibility()); | ||
411 | updateVisibilityOfQuickButtons(); | 148 | setTabPosition((QTabWidget::TabPosition) KonsoleSettings::tabBarPosition()); | ||
149 | setTabsClosable(KonsoleSettings::showQuickButtons()); | ||||
150 | setCornerWidget( KonsoleSettings::showQuickButtons() ? _newTabButton : nullptr, Qt::TopLeftCorner); | ||||
151 | | ||||
152 | if (isVisible() && KonsoleSettings::showQuickButtons()) { | ||||
153 | _newTabButton->setVisible(true); | ||||
412 | } | 154 | } | ||
413 | 155 | | |||
414 | void TabbedViewContainer::closeCurrentTab() | 156 | if (KonsoleSettings::tabBarUseUserStyleSheet()) { | ||
415 | { | 157 | setCssFromFile(KonsoleSettings::tabBarUserStyleSheetFile()); | ||
416 | if (_stackWidget->currentIndex() != -1) { | | |||
417 | emit closeTab(this, _stackWidget->widget(_stackWidget->currentIndex())); | | |||
418 | } | 158 | } | ||
419 | } | 159 | } | ||
420 | 160 | | |||
421 | void TabbedViewContainer::updateVisibilityOfQuickButtons() | 161 | void TabbedViewContainer::setCssFromFile(const QUrl &url) | ||
422 | { | 162 | { | ||
423 | const bool tabBarHidden = _tabBar->isHidden(); | 163 | // Let's only deal w/ local files for now | ||
424 | _newTabButton->setVisible(!tabBarHidden && ((features() & QuickNewView) != 0)); | 164 | if (!url.isLocalFile()) { | ||
425 | _closeTabButton->setVisible(!tabBarHidden && ((features() & QuickCloseView) != 0)); | 165 | setStyleSheet(KonsoleSettings::tabBarStyleSheet()); | ||
426 | } | 166 | } | ||
427 | 167 | | |||
428 | void TabbedViewContainer::setTabBarVisible(bool visible) | 168 | QFile file(url.toLocalFile()); | ||
429 | { | 169 | if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { | ||
430 | _tabBar->setVisible(visible); | 170 | setStyleSheet(KonsoleSettings::tabBarStyleSheet()); | ||
431 | updateVisibilityOfQuickButtons(); | | |||
432 | } | 171 | } | ||
433 | 172 | | |||
434 | QList<ViewContainer::NavigationPosition> TabbedViewContainer::supportedNavigationPositions() const | 173 | QString styleSheetText; | ||
435 | { | 174 | QTextStream in(&file); | ||
436 | return QList<NavigationPosition>() << NavigationPositionTop << NavigationPositionBottom; | 175 | while (!in.atEnd()) { | ||
176 | styleSheetText.append(in.readLine()); | ||||
177 | } | ||||
178 | setStyleSheet(styleSheetText); | ||||
437 | } | 179 | } | ||
438 | 180 | | |||
439 | void TabbedViewContainer::navigationPositionChanged(NavigationPosition position) | 181 | void TabbedViewContainer::moveActiveView(MoveDirection direction) | ||
440 | { | 182 | { | ||
441 | // this method assumes that there are three or zero items in the layout | 183 | const int currentIndex = indexOf(currentWidget()); | ||
442 | Q_ASSERT(_layout->count() == 3 || _layout->count() == 0); | 184 | int newIndex = direction == MoveViewLeft ? qMax(currentIndex - 1, 0) : qMin(currentIndex + 1, count() - 1); | ||
443 | 185 | | |||
444 | // clear all existing items from the layout | 186 | auto swappedWidget = widget(newIndex); | ||
445 | _layout->removeItem(_tabBarLayout); | 187 | auto currentWidget = widget(currentIndex); | ||
446 | _tabBarLayout->setParent(nullptr); // suppress the warning of "already has a parent" | 188 | auto swappedContext = _navigation[swappedWidget]; | ||
447 | _layout->removeWidget(_stackWidget); | 189 | auto currentContext = _navigation[currentWidget]; | ||
448 | _layout->removeWidget(searchBar()); | | |||
449 | 190 | | |||
450 | if (position == NavigationPositionTop) { | 191 | if (newIndex < currentIndex) { | ||
451 | _layout->insertLayout(-1, _tabBarLayout); | 192 | insertTab(newIndex, currentWidget, currentContext->icon(), currentContext->title()); | ||
452 | _layout->insertWidget(-1, _stackWidget); | 193 | insertTab(currentIndex, swappedWidget, swappedContext->icon(), swappedContext->title()); | ||
453 | _layout->insertWidget(-1, searchBar()); | | |||
454 | _tabBar->setShape(QTabBar::RoundedNorth); | | |||
455 | } else if (position == NavigationPositionBottom) { | | |||
456 | _layout->insertWidget(-1, _stackWidget); | | |||
457 | _layout->insertWidget(-1, searchBar()); | | |||
458 | _layout->insertLayout(-1, _tabBarLayout); | | |||
459 | _tabBar->setShape(QTabBar::RoundedSouth); | | |||
460 | } else { | 194 | } else { | ||
461 | Q_ASSERT(false); // should never reach here | 195 | insertTab(currentIndex, swappedWidget, swappedContext->icon(), swappedContext->title()); | ||
196 | insertTab(newIndex, currentWidget, currentContext->icon(), currentContext->title()); | ||||
462 | } | 197 | } | ||
198 | setCurrentIndex(newIndex); | ||||
463 | } | 199 | } | ||
464 | 200 | | |||
465 | void TabbedViewContainer::navigationTabWidthExpandingChanged(bool expand) | 201 | void TabbedViewContainer::addView(QWidget *view, ViewProperties *item, int index) | ||
466 | { | 202 | { | ||
467 | _tabBar->setExpanding(expand); | 203 | if (index == -1) { | ||
204 | addTab(view, item->icon(), item->title()); | ||||
205 | } else { | ||||
206 | insertTab(index, view, item->icon(), item->title()); | ||||
468 | } | 207 | } | ||
469 | 208 | | |||
470 | void TabbedViewContainer::navigationVisibilityChanged(NavigationVisibility mode) | 209 | _navigation[view] = item; | ||
471 | { | 210 | connect(item, &Konsole::ViewProperties::titleChanged, this, | ||
472 | if (mode == AlwaysShowNavigation && _tabBar->isHidden()) { | 211 | &Konsole::TabbedViewContainer::updateTitle); | ||
473 | setTabBarVisible(true); | 212 | connect(item, &Konsole::ViewProperties::iconChanged, this, | ||
213 | &Konsole::TabbedViewContainer::updateIcon); | ||||
214 | connect(item, &Konsole::ViewProperties::activity, this, | ||||
215 | &Konsole::TabbedViewContainer::updateActivity); | ||||
216 | connect(view, &QWidget::destroyed, this, | ||||
217 | &Konsole::TabbedViewContainer::viewDestroyed); | ||||
218 | emit viewAdded(view, item); | ||||
474 | } | 219 | } | ||
475 | 220 | | |||
476 | if (mode == AlwaysHideNavigation && !_tabBar->isHidden()) { | 221 | void TabbedViewContainer::viewDestroyed(QObject *view) | ||
477 | setTabBarVisible(false); | 222 | { | ||
478 | } | 223 | auto widget = static_cast<QWidget*>(view); | ||
224 | const auto idx = indexOf(widget); | ||||
479 | 225 | | |||
480 | if (mode == ShowNavigationAsNeeded) { | 226 | removeTab(idx); | ||
481 | dynamicTabBarVisibility(); | 227 | forgetView(widget); | ||
482 | } | | |||
483 | } | 228 | } | ||
484 | 229 | | |||
485 | void TabbedViewContainer::dynamicTabBarVisibility() | 230 | void TabbedViewContainer::forgetView(QWidget *view) | ||
486 | { | 231 | { | ||
487 | if (_tabBar->count() > 1 && _tabBar->isHidden()) { | 232 | _navigation.remove(view); | ||
488 | setTabBarVisible(true); | 233 | emit viewRemoved(view); | ||
489 | } | 234 | if (count() == 0) { | ||
490 | 235 | emit empty(this); | |||
491 | if (_tabBar->count() < 2 && !_tabBar->isHidden()) { | | |||
492 | setTabBarVisible(false); | | |||
493 | } | 236 | } | ||
494 | } | 237 | } | ||
495 | 238 | | |||
496 | void TabbedViewContainer::setStyleSheet(const QString &styleSheet) | 239 | void TabbedViewContainer::removeView(QWidget *view) | ||
497 | { | 240 | { | ||
498 | _tabBar->setStyleSheet(styleSheet); | 241 | const int idx = indexOf(view); | ||
242 | disconnect(view, &QWidget::destroyed, this, &Konsole::TabbedViewContainer::viewDestroyed); | ||||
243 | removeTab(idx); | ||||
244 | forgetView(view); | ||||
499 | } | 245 | } | ||
500 | 246 | | |||
501 | // TODO: Only called via dbus method - remove | 247 | void TabbedViewContainer::activateNextView() | ||
502 | void TabbedViewContainer::navigationTextModeChanged(bool useTextWidth) | | |||
503 | { | 248 | { | ||
504 | // Qt 5.9 changed how tabs are displayed | 249 | QWidget *active = currentWidget(); | ||
505 | if (useTextWidth) { | 250 | int index = indexOf(active); | ||
506 | _tabBar->setStyleSheet(QStringLiteral("QTabBar::tab { }")); | 251 | setCurrentIndex(index == count() - 1 ? 0 : index + 1); | ||
507 | _tabBar->setExpanding(false); | | |||
508 | _tabBar->setElideMode(Qt::ElideNone); | | |||
509 | } else { | | |||
510 | _tabBar->setStyleSheet(QStringLiteral("QTabBar::tab { min-width: 2em; max-width: 25em }")); | | |||
511 | _tabBar->setExpanding(true); | | |||
512 | _tabBar->setElideMode(Qt::ElideLeft); | | |||
513 | } | | |||
514 | } | 252 | } | ||
515 | 253 | | |||
516 | TabbedViewContainer::~TabbedViewContainer() | 254 | void TabbedViewContainer::activateLastView() | ||
517 | { | 255 | { | ||
518 | if (!_containerWidget.isNull()) { | 256 | setCurrentIndex(count() - 1); | ||
519 | _containerWidget->deleteLater(); | | |||
520 | } | | |||
521 | } | 257 | } | ||
522 | 258 | | |||
523 | void TabbedViewContainer::startTabDrag(int index) | 259 | void TabbedViewContainer::activatePreviousView() | ||
524 | { | 260 | { | ||
525 | QPointer<QDrag> drag = new QDrag(_tabBar); | 261 | QWidget *active = currentWidget(); | ||
526 | const QRect tabRect = _tabBar->tabRect(index); | 262 | int index = indexOf(active); | ||
527 | QPixmap tabPixmap = _tabBar->dragDropPixmap(index); | 263 | setCurrentIndex(index == 0 ? count() - 1 : index - 1); | ||
528 | | ||||
529 | drag->setPixmap(tabPixmap); | | |||
530 | | ||||
531 | // offset the tab position so the tab will follow the cursor exactly | | |||
532 | // where it was clicked (as opposed to centering on the origin of the pixmap) | | |||
533 | QPoint mappedPos = _tabBar->mapFromGlobal(QCursor::pos()); | | |||
534 | mappedPos.rx() -= tabRect.x(); | | |||
535 | | ||||
536 | drag->setHotSpot(mappedPos); | | |||
537 | | ||||
538 | const int id = viewProperties(views()[index])->identifier(); | | |||
539 | QWidget *view = views()[index]; | | |||
540 | drag->setMimeData(ViewProperties::createMimeData(id)); | | |||
541 | | ||||
542 | // start dragging | | |||
543 | const Qt::DropAction action = drag->exec(); | | |||
544 | | ||||
545 | if ((!drag.isNull()) && (drag->target() != nullptr)) { | | |||
546 | switch (action) { | | |||
547 | case Qt::MoveAction: | | |||
548 | // The MoveAction indicates the widget has been successfully | | |||
549 | // moved into another tabbar/container, so remove the widget in | | |||
550 | // current tabbar/container. | | |||
551 | // | | |||
552 | // Deleting the view may cause the view container to be deleted, | | |||
553 | // which will also delete the QDrag object. This can cause a | | |||
554 | // crash if Qt's internal drag-and-drop handling tries to delete | | |||
555 | // it later. | | |||
556 | // | | |||
557 | // For now set the QDrag's parent to 0 so that it won't be | | |||
558 | // deleted if this view container is destroyed. | | |||
559 | // | | |||
560 | // FIXME: Resolve this properly | | |||
561 | drag->setParent(nullptr); | | |||
562 | removeView(view); | | |||
563 | break; | | |||
564 | case Qt::IgnoreAction: | | |||
565 | // The IgnoreAction is used by the tabbar to indicate the | | |||
566 | // special case of dropping one tab into its existing position. | | |||
567 | // So nothing need to do here. | | |||
568 | break; | | |||
569 | default: | | |||
570 | break; | | |||
571 | } | | |||
572 | } else { | | |||
573 | // if the tab is dragged onto something that does not accept this | | |||
574 | // drop(for example, a different application or a different konsole | | |||
575 | // process), then detach the tab to achieve the effect of "dragging tab | | |||
576 | // out of current window and into its own window" | | |||
577 | // | | |||
578 | // It feels unnatural to do the detach when this is only one tab in the | | |||
579 | // tabbar | | |||
580 | if (_tabBar->count() > 1) { | | |||
581 | emit detachTab(this, view); | | |||
582 | } | | |||
583 | } | | |||
584 | delete drag; | | |||
585 | } | | |||
586 | | ||||
587 | void TabbedViewContainer::querySourceIndex(const QDropEvent *event, int &sourceIndex) | | |||
588 | { | | |||
589 | const int droppedId = ViewProperties::decodeMimeData(event->mimeData()); | | |||
590 | | ||||
591 | const QList<QWidget *> viewList = views(); | | |||
592 | const int count = viewList.count(); | | |||
593 | int index = -1; | | |||
594 | for (index = 0; index < count; index++) { | | |||
595 | const int id = viewProperties(viewList[index])->identifier(); | | |||
596 | if (id == droppedId) { | | |||
597 | break; | | |||
598 | } | 264 | } | ||
265 | | ||||
266 | ViewProperties *TabbedViewContainer::viewProperties(QWidget *view) const | ||||
267 | { | ||||
268 | Q_ASSERT(_navigation.contains(view)); | ||||
269 | return _navigation[view]; | ||||
599 | } | 270 | } | ||
600 | 271 | | |||
601 | sourceIndex = index; | 272 | QList<QWidget *> TabbedViewContainer::widgetsForItem(ViewProperties *item) const | ||
273 | { | ||||
274 | return _navigation.keys(item); | ||||
602 | } | 275 | } | ||
603 | 276 | | |||
604 | void TabbedViewContainer::onMoveViewRequest(int index, const QDropEvent *event, bool &success, | 277 | void TabbedViewContainer::closeCurrentTab() | ||
I'm not sure if konsole follows the kdelibs/qt coding style guidelines, but in case it does iirc auto should not be used here. sandsmark: I'm not sure if konsole follows the kdelibs/qt coding style guidelines, but in case it does… | |||||
We have some 'auto' in the code before this one so I used here. the kdelibs coding style was written before C++11, perhaps we should update it for future generations. I don't use auto where the type is ambiguous or when it's impossible for the human eye to know what's the type, but since here it's an list-of-actions, it's easy to see that auto will be a QAction*. tcanabrava: We have some 'auto' in the code before this one so I used here. the kdelibs coding style was… | |||||
sandsmark: remove dead code | |||||
sandsmark: again, breaks selecting the new profile when opening a tab. | |||||
sandsmark: maybe use qOverload instead of the ugly static_cast? | |||||
qOverload needs C++14, konsole is being compiled currently with C++11 - if you are ok with that I can enable C++ 14 for it. tcanabrava: qOverload needs C++14, konsole is being compiled currently with C++11 - if you are ok with that… | |||||
sandsmark: same with qt coding style and auto | |||||
605 | TabbedViewContainer *sourceTabbedContainer) | | |||
606 | { | 278 | { | ||
607 | const int droppedId = ViewProperties::decodeMimeData(event->mimeData()); | 279 | if (currentIndex() != -1) { | ||
608 | emit moveViewRequest(index, droppedId, success, sourceTabbedContainer); | 280 | closeTerminalTab(currentIndex()); | ||
281 | } | ||||
609 | } | 282 | } | ||
610 | 283 | | |||
611 | void TabbedViewContainer::tabDoubleClicked(int index) | 284 | void TabbedViewContainer::tabDoubleClicked(int index) | ||
sandsmark: extremely minor coding style nitpick, avoid abbreviations. | |||||
in case konsole is the opposite of the qt coding style wrt. auto this should also be auto, I guess. sandsmark: in case konsole is the opposite of the qt coding style wrt. auto this should also be auto, I… | |||||
sandsmark: the «put new tab after current tab» seems to also be broken. | |||||
612 | { | 285 | { | ||
sandsmark: same issues with auto wrt. qt coding style | |||||
613 | if (index >= 0) { | 286 | if (index >= 0) { | ||
614 | renameTab(index); | 287 | renameTab(index); | ||
615 | } else { | 288 | } else { | ||
616 | emit newViewRequest(); | 289 | emit newViewRequest(); | ||
617 | } | 290 | } | ||
618 | } | 291 | } | ||
619 | 292 | | |||
620 | void TabbedViewContainer::renameTab(int index) | 293 | void TabbedViewContainer::renameTab(int index) | ||
621 | { | 294 | { | ||
622 | viewProperties(views()[index])->rename(); | 295 | if (index != -1) { | ||
296 | _navigation[widget(index)]->rename(); | ||||
297 | } | ||||
sandsmark: outdated comment or is it broken? | |||||
tcanabrava: outdated. | |||||
623 | } | 298 | } | ||
624 | 299 | | |||
625 | void TabbedViewContainer::openTabContextMenu(const QPoint &point) | 300 | void TabbedViewContainer::openTabContextMenu(const QPoint &point) | ||
626 | { | 301 | { | ||
627 | if (point.isNull()) { | 302 | if (point.isNull()) { | ||
628 | return; | 303 | return; | ||
629 | } | 304 | } | ||
630 | 305 | | |||
631 | _contextMenuTabIndex = _tabBar->tabAt(point); | 306 | _contextMenuTabIndex = tabBar()->tabAt(point); | ||
632 | if (_contextMenuTabIndex < 0) { | 307 | if (_contextMenuTabIndex < 0) { | ||
633 | return; | 308 | return; | ||
634 | } | 309 | } | ||
635 | 310 | | |||
636 | #if defined(ENABLE_DETACHING) | 311 | //TODO: add a countChanged signal so we can remove this for. | ||
637 | // Enable 'Detach Tab' menu item only if there is more than 1 tab | 312 | // Detaching in mac causes crashes. | ||
638 | // Note: the code is coupled with that action's position within the menu | 313 | const auto isDarwin = QOperatingSystemVersion::currentType() == QOperatingSystemVersion::MacOS; | ||
639 | QAction *detachAction = _contextPopupMenu->actions().at(0); | 314 | for(auto action : _contextPopupMenu->actions()) { | ||
640 | detachAction->setEnabled(_tabBar->count() > 1); | 315 | if (action->objectName() == QStringLiteral("tab-detach")) { | ||
641 | #endif | 316 | action->setEnabled( !isDarwin && count() > 1); | ||
317 | } | ||||
318 | } | ||||
642 | 319 | | |||
643 | // Add the read-only action | 320 | // Add the read-only action | ||
644 | SessionController *sessionController = qobject_cast<SessionController*>(viewProperties(views()[_contextMenuTabIndex])); | 321 | auto controller = _navigation[widget(_contextMenuTabIndex)]; | ||
322 | auto sessionController = qobject_cast<SessionController*>(controller); | ||||
323 | | ||||
645 | if (sessionController != nullptr) { | 324 | if (sessionController != nullptr) { | ||
646 | auto collection = sessionController->actionCollection(); | 325 | auto collection = sessionController->actionCollection(); | ||
647 | auto readonlyAction = collection->action(QStringLiteral("view-readonly")); | 326 | auto readonlyAction = collection->action(QStringLiteral("view-readonly")); | ||
648 | if (readonlyAction != nullptr) { | 327 | if (readonlyAction != nullptr) { | ||
649 | const auto readonlyActions = _contextPopupMenu->actions(); | 328 | const auto readonlyActions = _contextPopupMenu->actions(); | ||
650 | _contextPopupMenu->insertAction(readonlyActions.last(), readonlyAction); | 329 | _contextPopupMenu->insertAction(readonlyActions.last(), readonlyAction); | ||
651 | } | 330 | } | ||
652 | 331 | | |||
653 | // Disable tab rename | 332 | // Disable tab rename | ||
654 | for (auto &action : _contextPopupMenu->actions()) { | 333 | for (auto &action : _contextPopupMenu->actions()) { | ||
655 | if (action->objectName() == QStringLiteral("edit-rename")) { | 334 | if (action->objectName() == QStringLiteral("edit-rename")) { | ||
656 | action->setEnabled(!sessionController->isReadOnly()); | 335 | action->setEnabled(!sessionController->isReadOnly()); | ||
657 | break; | 336 | break; | ||
658 | } | 337 | } | ||
659 | } | 338 | } | ||
660 | } | 339 | } | ||
661 | 340 | | |||
662 | _contextPopupMenu->exec(_tabBar->mapToGlobal(point)); | 341 | _contextPopupMenu->exec(tabBar()->mapToGlobal(point)); | ||
663 | } | | |||
664 | | ||||
665 | void TabbedViewContainer::tabContextMenuCloseTab() | | |||
666 | { | | |||
667 | _tabBar->setCurrentIndex(_contextMenuTabIndex);// Required for this to work | | |||
668 | emit closeTab(this, _stackWidget->widget(_contextMenuTabIndex)); | | |||
669 | } | | |||
670 | | ||||
671 | void TabbedViewContainer::tabContextMenuDetachTab() | | |||
672 | { | | |||
673 | emit detachTab(this, _stackWidget->widget(_contextMenuTabIndex)); | | |||
674 | } | | |||
675 | | ||||
676 | void TabbedViewContainer::tabContextMenuRenameTab() | | |||
677 | { | | |||
678 | renameTab(_contextMenuTabIndex); | | |||
679 | } | | |||
680 | | ||||
681 | void TabbedViewContainer::moveViewWidget(int fromIndex, int toIndex) | | |||
682 | { | | |||
683 | QString text = _tabBar->tabText(fromIndex); | | |||
684 | QIcon icon = _tabBar->tabIcon(fromIndex); | | |||
685 | | ||||
686 | // FIXME (KF5?)- This will lose properties of the tab other than | | |||
687 | // their text and icon when moving them | | |||
688 | | ||||
689 | QWidget *widget = _stackWidget->widget(fromIndex); | | |||
690 | // this also removes the tab from the tab bar | | |||
691 | _stackWidget->removeWidget(widget); | | |||
692 | _stackWidget->insertWidget(toIndex, widget); | | |||
693 | | ||||
694 | _tabBar->insertTab(toIndex, icon, text); | | |||
695 | | ||||
696 | if (navigationVisibility() == ShowNavigationAsNeeded) { | | |||
697 | dynamicTabBarVisibility(); | | |||
698 | } | | |||
699 | } | 342 | } | ||
700 | 343 | | |||
701 | void TabbedViewContainer::currentTabChanged(int index) | 344 | void TabbedViewContainer::currentTabChanged(int index) | ||
702 | { | 345 | { | ||
703 | _stackWidget->setCurrentIndex(index); | 346 | setCurrentIndex(index); | ||
704 | if (_stackWidget->widget(index) != nullptr) { | 347 | if (widget(index) != nullptr) { | ||
705 | emit activeViewChanged(_stackWidget->widget(index)); | 348 | emit activeViewChanged(widget(index)); | ||
706 | } | 349 | } | ||
707 | 350 | | |||
708 | // clear activity indicators | 351 | // clear activity indicators | ||
709 | setTabActivity(index, false); | 352 | setTabActivity(index, false); | ||
710 | } | 353 | } | ||
711 | 354 | | |||
712 | void TabbedViewContainer::wheelScrolled(int delta) | 355 | void TabbedViewContainer::wheelScrolled(int delta) | ||
713 | { | 356 | { | ||
714 | if (delta < 0) { | 357 | if (delta < 0) { | ||
715 | activateNextView(); | 358 | activateNextView(); | ||
716 | } else { | 359 | } else { | ||
717 | activatePreviousView(); | 360 | activatePreviousView(); | ||
718 | } | 361 | } | ||
719 | } | 362 | } | ||
720 | 363 | | |||
721 | QWidget *TabbedViewContainer::containerWidget() const | | |||
722 | { | | |||
723 | return _containerWidget; | | |||
724 | } | | |||
725 | | ||||
726 | QWidget *TabbedViewContainer::activeView() const | | |||
727 | { | | |||
728 | return _stackWidget->currentWidget(); | | |||
729 | } | | |||
730 | | ||||
731 | void TabbedViewContainer::setActiveView(QWidget *view) | | |||
732 | { | | |||
733 | const int index = _stackWidget->indexOf(view); | | |||
734 | | ||||
735 | Q_ASSERT(index != -1); | | |||
736 | | ||||
737 | _stackWidget->setCurrentWidget(view); | | |||
738 | _tabBar->setCurrentIndex(index); | | |||
739 | } | | |||
740 | | ||||
741 | void TabbedViewContainer::addViewWidget(QWidget *view, int index) | | |||
742 | { | | |||
743 | _stackWidget->insertWidget(index, view); | | |||
744 | _stackWidget->updateGeometry(); | | |||
745 | | ||||
746 | ViewProperties *item = viewProperties(view); | | |||
747 | connect(item, &Konsole::ViewProperties::titleChanged, this, | | |||
748 | &Konsole::TabbedViewContainer::updateTitle); | | |||
749 | connect(item, &Konsole::ViewProperties::iconChanged, this, | | |||
750 | &Konsole::TabbedViewContainer::updateIcon); | | |||
751 | connect(item, &Konsole::ViewProperties::activity, this, | | |||
752 | &Konsole::TabbedViewContainer::updateActivity); | | |||
753 | | ||||
754 | _tabBar->insertTab(index, item->icon(), item->title()); | | |||
755 | | ||||
756 | if (navigationVisibility() == ShowNavigationAsNeeded) { | | |||
757 | dynamicTabBarVisibility(); | | |||
758 | } | | |||
759 | } | | |||
760 | | ||||
761 | void TabbedViewContainer::removeViewWidget(QWidget *view) | | |||
762 | { | | |||
763 | if (_stackWidget.isNull()) { | | |||
764 | return; | | |||
765 | } | | |||
766 | _stackWidget->removeWidget(view); | | |||
767 | } | | |||
768 | | ||||
769 | void TabbedViewContainer::widgetRemoved(int index) | | |||
770 | { | | |||
771 | Q_ASSERT(index != -1); | | |||
772 | | ||||
773 | _tabBar->removeTab(index); | | |||
774 | | ||||
775 | if (navigationVisibility() == ShowNavigationAsNeeded) { | | |||
776 | dynamicTabBarVisibility(); | | |||
777 | } | | |||
778 | } | | |||
779 | | ||||
780 | void TabbedViewContainer::setTabActivity(int index, bool activity) | 364 | void TabbedViewContainer::setTabActivity(int index, bool activity) | ||
781 | { | 365 | { | ||
782 | const QPalette &palette = _tabBar->palette(); | 366 | const QPalette &palette = tabBar()->palette(); | ||
783 | KColorScheme colorScheme(palette.currentColorGroup()); | 367 | KColorScheme colorScheme(palette.currentColorGroup()); | ||
784 | const QColor colorSchemeActive = colorScheme.foreground(KColorScheme::ActiveText).color(); | 368 | const QColor colorSchemeActive = colorScheme.foreground(KColorScheme::ActiveText).color(); | ||
785 | 369 | | |||
786 | const QColor normalColor = palette.text().color(); | 370 | const QColor normalColor = palette.text().color(); | ||
787 | const QColor activityColor = KColorUtils::mix(normalColor, colorSchemeActive); | 371 | const QColor activityColor = KColorUtils::mix(normalColor, colorSchemeActive); | ||
788 | 372 | | |||
789 | QColor color = activity ? activityColor : QColor(); | 373 | QColor color = activity ? activityColor : QColor(); | ||
790 | 374 | | |||
791 | if (color != _tabBar->tabTextColor(index)) { | 375 | if (color != tabBar()->tabTextColor(index)) { | ||
792 | _tabBar->setTabTextColor(index, color); | 376 | tabBar()->setTabTextColor(index, color); | ||
793 | } | 377 | } | ||
794 | } | 378 | } | ||
795 | 379 | | |||
796 | void TabbedViewContainer::updateActivity(ViewProperties *item) | 380 | void TabbedViewContainer::updateActivity(ViewProperties *item) | ||
797 | { | 381 | { | ||
798 | foreach (QWidget *widget, widgetsForItem(item)) { | 382 | foreach (QWidget *widget, widgetsForItem(item)) { | ||
799 | const int index = _stackWidget->indexOf(widget); | 383 | const int index = indexOf(widget); | ||
800 | 384 | | |||
801 | if (index != _stackWidget->currentIndex()) { | 385 | if (index != currentIndex()) { | ||
802 | setTabActivity(index, true); | 386 | setTabActivity(index, true); | ||
803 | } | 387 | } | ||
804 | } | 388 | } | ||
805 | } | 389 | } | ||
806 | 390 | | |||
807 | void TabbedViewContainer::updateTitle(ViewProperties *item) | 391 | void TabbedViewContainer::updateTitle(ViewProperties *item) | ||
808 | { | 392 | { | ||
809 | foreach (QWidget *widget, widgetsForItem(item)) { | 393 | foreach (QWidget *widget, widgetsForItem(item)) { | ||
810 | const int index = _stackWidget->indexOf(widget); | 394 | const int index = indexOf(widget); | ||
811 | QString tabText = item->title(); | 395 | QString tabText = item->title(); | ||
812 | 396 | | |||
813 | _tabBar->setTabToolTip(index, tabText); | 397 | setTabToolTip(index, tabText); | ||
814 | 398 | | |||
815 | // To avoid having & replaced with _ (shortcut indicator) | 399 | // To avoid having & replaced with _ (shortcut indicator) | ||
816 | tabText.replace(QLatin1Char('&'), QLatin1String("&&")); | 400 | tabText.replace(QLatin1Char('&'), QLatin1String("&&")); | ||
817 | _tabBar->setTabText(index, tabText); | 401 | setTabText(index, tabText); | ||
818 | } | 402 | } | ||
819 | } | 403 | } | ||
820 | 404 | | |||
821 | void TabbedViewContainer::updateIcon(ViewProperties *item) | 405 | void TabbedViewContainer::updateIcon(ViewProperties *item) | ||
822 | { | 406 | { | ||
823 | foreach (QWidget *widget, widgetsForItem(item)) { | 407 | foreach (QWidget *widget, widgetsForItem(item)) { | ||
824 | const int index = _stackWidget->indexOf(widget); | 408 | const int index = indexOf(widget); | ||
825 | _tabBar->setTabIcon(index, item->icon()); | 409 | setTabIcon(index, item->icon()); | ||
410 | } | ||||
826 | } | 411 | } | ||
412 | | ||||
413 | void TabbedViewContainer::closeTerminalTab(int idx) { | ||||
414 | auto currWidget = widget(idx); | ||||
415 | auto controller = qobject_cast<SessionController *>(_navigation[currWidget]); | ||||
416 | controller->closeSession(); | ||||
827 | } | 417 | } | ||
828 | 418 | | |||
829 | ViewManager *TabbedViewContainer::connectedViewManager() | 419 | ViewManager *TabbedViewContainer::connectedViewManager() | ||
830 | { | 420 | { | ||
831 | return _connectedViewManager; | 421 | return _connectedViewManager; | ||
832 | } | 422 | } |
for some reason phabricator doesn't seem to show the patch correctly, but looking at the diff in git a new newtabbutton was added.
but the new button isn't laid out properly (tiny and top-aligned).