Changeset View
Changeset View
Standalone View
Standalone View
src/ViewSplitter.cpp
Show All 18 Lines | 1 | /* | |||
---|---|---|---|---|---|
19 | 02110-1301 USA. | 19 | 02110-1301 USA. | ||
20 | */ | 20 | */ | ||
21 | 21 | | |||
22 | // Own | 22 | // Own | ||
23 | #include "ViewSplitter.h" | 23 | #include "ViewSplitter.h" | ||
24 | 24 | | |||
25 | // Qt | 25 | // Qt | ||
26 | #include <QDebug> | 26 | #include <QDebug> | ||
27 | #include <QChildEvent> | ||||
27 | 28 | | |||
28 | // Konsole | 29 | // Konsole | ||
29 | #include "ViewContainer.h" | 30 | #include "ViewContainer.h" | ||
31 | #include "TerminalDisplay.h" | ||||
30 | 32 | | |||
31 | using Konsole::ViewSplitter; | 33 | using Konsole::ViewSplitter; | ||
32 | using Konsole::TabbedViewContainer; | 34 | using Konsole::TerminalDisplay; | ||
33 | 35 | | |||
34 | ViewSplitter::ViewSplitter(QWidget *parent) : | 36 | //TODO: Connect the TerminalDisplay destroyed signal here. | ||
35 | QSplitter(parent), | | |||
36 | _containers(QList<TabbedViewContainer *>()), | | |||
37 | _recursiveSplitting(true) | | |||
38 | { | | |||
39 | } | | |||
40 | 37 | | |||
41 | void ViewSplitter::childEmpty(ViewSplitter *splitter) | 38 | ViewSplitter::ViewSplitter(QWidget *parent) : | ||
39 | QSplitter(parent) | ||||
42 | { | 40 | { | ||
43 | delete splitter; | | |||
44 | | ||||
45 | if (count() == 0) { | | |||
46 | emit empty(this); | | |||
47 | } | | |||
48 | } | 41 | } | ||
49 | 42 | | |||
50 | void ViewSplitter::adjustContainerSize(TabbedViewContainer *container, int percentage) | 43 | void ViewSplitter::adjustTerminalDisplaySize(TerminalDisplay *container, int percentage) | ||
51 | { | 44 | { | ||
52 | int containerIndex = indexOf(container); | 45 | int containerIndex = indexOf(container); | ||
53 | 46 | | |||
54 | Q_ASSERT(containerIndex != -1); | 47 | Q_ASSERT(containerIndex != -1); | ||
55 | 48 | | |||
56 | QList<int> containerSizes = sizes(); | 49 | QList<int> containerSizes = sizes(); | ||
57 | 50 | | |||
58 | const int oldSize = containerSizes[containerIndex]; | 51 | const int oldSize = containerSizes[containerIndex]; | ||
Show All 22 Lines | 73 | while ((splitter == nullptr) && (widget != nullptr)) { | |||
81 | splitter = qobject_cast<ViewSplitter *>(widget); | 74 | splitter = qobject_cast<ViewSplitter *>(widget); | ||
82 | widget = widget->parentWidget(); | 75 | widget = widget->parentWidget(); | ||
83 | } | 76 | } | ||
84 | 77 | | |||
85 | Q_ASSERT(splitter); | 78 | Q_ASSERT(splitter); | ||
86 | return splitter; | 79 | return splitter; | ||
87 | } | 80 | } | ||
88 | 81 | | |||
89 | void ViewSplitter::registerContainer(TabbedViewContainer *container) | | |||
90 | { | | |||
91 | _containers << container; | | |||
92 | connect(container, SIGNAL(empty(TabbedViewContainer*)), this, SLOT(containerEmpty(TabbedViewContainer*))); | | |||
93 | } | | |||
94 | | ||||
95 | void ViewSplitter::unregisterContainer(TabbedViewContainer *container) | | |||
96 | { | | |||
97 | _containers.removeAll(container); | | |||
98 | disconnect(container, nullptr, this, nullptr); | | |||
99 | } | | |||
100 | | ||||
101 | void ViewSplitter::updateSizes() | 82 | void ViewSplitter::updateSizes() | ||
102 | { | 83 | { | ||
103 | int space; | 84 | int space; | ||
104 | 85 | | |||
105 | if (orientation() == Qt::Horizontal) { | 86 | if (orientation() == Qt::Horizontal) { | ||
106 | space = width() / count(); | 87 | space = width() / count(); | ||
107 | } else { | 88 | } else { | ||
108 | space = height() / count(); | 89 | space = height() / count(); | ||
109 | } | 90 | } | ||
110 | 91 | | |||
111 | QList<int> widgetSizes; | 92 | QList<int> widgetSizes; | ||
112 | const int widgetCount = count(); | 93 | const int widgetCount = count(); | ||
113 | widgetSizes.reserve(widgetCount); | 94 | widgetSizes.reserve(widgetCount); | ||
114 | for (int i = 0; i < widgetCount; i++) { | 95 | for (int i = 0; i < widgetCount; i++) { | ||
115 | widgetSizes << space; | 96 | widgetSizes << space; | ||
116 | } | 97 | } | ||
117 | 98 | | |||
118 | setSizes(widgetSizes); | 99 | setSizes(widgetSizes); | ||
119 | } | 100 | } | ||
120 | 101 | | |||
121 | void ViewSplitter::setRecursiveSplitting(bool recursive) | 102 | void ViewSplitter::addTerminalDisplay(TerminalDisplay *terminalDisplay, Qt::Orientation containerOrientation) | ||
122 | { | | |||
123 | _recursiveSplitting = recursive; | | |||
124 | } | | |||
125 | | ||||
126 | bool ViewSplitter::recursiveSplitting() const | | |||
127 | { | | |||
128 | return _recursiveSplitting; | | |||
129 | } | | |||
130 | | ||||
131 | void ViewSplitter::removeContainer(TabbedViewContainer *container) | | |||
132 | { | | |||
133 | Q_ASSERT(containers().contains(container)); | | |||
134 | | ||||
135 | unregisterContainer(container); | | |||
136 | } | | |||
137 | | ||||
138 | void ViewSplitter::addContainer(TabbedViewContainer *container, Qt::Orientation containerOrientation) | | |||
139 | { | 103 | { | ||
140 | ViewSplitter *splitter = activeSplitter(); | 104 | ViewSplitter *splitter = activeSplitter(); | ||
141 | 105 | | |||
142 | if (splitter->count() < 2 | 106 | if (splitter->count() < 2 | ||
143 | || containerOrientation == splitter->orientation() | 107 | || containerOrientation == splitter->orientation()) { | ||
144 | || !_recursiveSplitting) { | 108 | splitter->addWidget(terminalDisplay); | ||
145 | splitter->registerContainer(container); | | |||
146 | splitter->addWidget(container); | | |||
147 | 109 | | |||
148 | if (splitter->orientation() != containerOrientation) { | 110 | if (splitter->orientation() != containerOrientation) { | ||
149 | splitter->setOrientation(containerOrientation); | 111 | splitter->setOrientation(containerOrientation); | ||
150 | } | 112 | } | ||
151 | | ||||
152 | splitter->updateSizes(); | 113 | splitter->updateSizes(); | ||
153 | } else { | 114 | } else { | ||
154 | auto newSplitter = new ViewSplitter(this); | 115 | auto newSplitter = new ViewSplitter(); | ||
155 | connect(newSplitter, &Konsole::ViewSplitter::empty, splitter, | | |||
156 | &Konsole::ViewSplitter::childEmpty); | | |||
157 | | ||||
158 | TabbedViewContainer *oldContainer = splitter->activeContainer(); | | |||
159 | const int oldContainerIndex = splitter->indexOf(oldContainer); | | |||
160 | | ||||
161 | splitter->unregisterContainer(oldContainer); | | |||
162 | | ||||
163 | newSplitter->registerContainer(oldContainer); | | |||
164 | newSplitter->registerContainer(container); | | |||
165 | 116 | | |||
166 | newSplitter->addWidget(oldContainer); | 117 | TerminalDisplay *oldTerminalDisplay = splitter->activeTerminalDisplay(); | ||
167 | newSplitter->addWidget(container); | 118 | const int oldContainerIndex = splitter->indexOf(oldTerminalDisplay); | ||
119 | newSplitter->addWidget(oldTerminalDisplay); | ||||
120 | newSplitter->addWidget(terminalDisplay); | ||||
168 | newSplitter->setOrientation(containerOrientation); | 121 | newSplitter->setOrientation(containerOrientation); | ||
169 | newSplitter->updateSizes(); | 122 | newSplitter->updateSizes(); | ||
170 | newSplitter->show(); | 123 | newSplitter->show(); | ||
171 | 124 | | |||
172 | splitter->insertWidget(oldContainerIndex, newSplitter); | 125 | splitter->insertWidget(oldContainerIndex, newSplitter); | ||
173 | } | 126 | } | ||
174 | } | 127 | } | ||
175 | 128 | | |||
176 | void ViewSplitter::containerEmpty(TabbedViewContainer * myContainer) | 129 | void ViewSplitter::childEvent(QChildEvent *event) | ||
177 | { | 130 | { | ||
178 | _containers.removeAll(myContainer); | 131 | QSplitter::childEvent(event); | ||
132 | | ||||
133 | if (event->removed()) { | ||||
179 | if (count() == 0) { | 134 | if (count() == 0) { | ||
180 | emit empty(this); | 135 | deleteLater(); | ||
181 | } | 136 | } | ||
182 | 137 | if (!findChild<TerminalDisplay*>()) { | |||
183 | int children = 0; | 138 | deleteLater(); | ||
184 | foreach (auto container, _containers) { | | |||
185 | children += container->count(); | | |||
186 | } | 139 | } | ||
187 | | ||||
188 | if (children == 0) { | | |||
189 | emit allContainersEmpty(); | | |||
190 | } | 140 | } | ||
141 | } | ||||
142 | | ||||
143 | void ViewSplitter::handleFocusDirection(Qt::Orientation orientation, int direction) | ||||
144 | { | ||||
145 | auto terminalDisplay = activeTerminalDisplay(); | ||||
146 | auto activeViewSplitter = qobject_cast<ViewSplitter*>(terminalDisplay->parentWidget()); | ||||
147 | auto idx = activeViewSplitter->indexOf(terminalDisplay); | ||||
191 | 148 | | |||
192 | // This container is no more, try to find another container to focus. | 149 | // Easy, the orientation of this splitter is the same as we are looking for. | ||
193 | ViewSplitter *currentSplitter = activeSplitter(); | 150 | if (activeViewSplitter->orientation() == orientation && | ||
194 | while(qobject_cast<ViewSplitter*>(currentSplitter->parent())) { | 151 | ((direction < 0 && idx > 0) || (direction > 0 && idx < activeViewSplitter->count() - 1))) { | ||
195 | currentSplitter = qobject_cast<ViewSplitter*>(currentSplitter->parent()); | 152 | auto nextPossibleTerminal = qobject_cast<TerminalDisplay*>(activeViewSplitter->widget(idx + direction)); | ||
153 | if (nextPossibleTerminal) { | ||||
154 | nextPossibleTerminal->setFocus(Qt::OtherFocusReason); | ||||
155 | return; | ||||
196 | } | 156 | } | ||
197 | 157 | | |||
198 | for(auto tabWidget : currentSplitter->findChildren<TabbedViewContainer*>()) { | 158 | // element is not a terminal display but a splitter with perhaps more splitters and terminals. | ||
199 | if (tabWidget != myContainer && tabWidget->count()) { | 159 | // choose one element and focus it. | ||
200 | tabWidget->setCurrentIndex(0); | 160 | auto nextPossibleSplitter = qobject_cast<ViewSplitter*>(activeViewSplitter->widget(idx + direction)); | ||
161 | if (nextPossibleSplitter) { | ||||
162 | nextPossibleTerminal = nextPossibleSplitter->findChild<TerminalDisplay*>(); | ||||
163 | if (nextPossibleTerminal) { | ||||
164 | nextPossibleTerminal->setFocus(Qt::OtherFocusReason); | ||||
201 | } | 165 | } | ||
166 | return; | ||||
202 | } | 167 | } | ||
168 | return; | ||||
203 | } | 169 | } | ||
204 | 170 | | |||
205 | void ViewSplitter::activateNextContainer() | 171 | // Hard, we are in a horizontal splitter or we are in the top of the vertical splitter. | ||
206 | { | 172 | // we need to get a splitter parent that we can to, following the parent chain. | ||
207 | TabbedViewContainer *active = activeContainer(); | 173 | ViewSplitter *parentTerminalWidget = nullptr; | ||
174 | ViewSplitter *oldParent = activeViewSplitter; | ||||
175 | do { | ||||
176 | parentTerminalWidget = qobject_cast<ViewSplitter*>( | ||||
177 | parentTerminalWidget ? parentTerminalWidget->parentWidget() | ||||
178 | : activeViewSplitter->parentWidget()); | ||||
208 | 179 | | |||
209 | int index = _containers.indexOf(active); | 180 | if (parentTerminalWidget) { | ||
181 | idx = parentTerminalWidget->indexOf(oldParent); | ||||
182 | } | ||||
183 | oldParent = parentTerminalWidget; | ||||
184 | } while (parentTerminalWidget && parentTerminalWidget->orientation() != orientation); | ||||
210 | 185 | | |||
211 | if (index == -1) { | 186 | if (!parentTerminalWidget) { | ||
212 | return; | 187 | return; | ||
213 | } | 188 | } | ||
214 | 189 | | |||
215 | if (index == _containers.count() - 1) { | 190 | if ((direction < 0 && idx > 0) || (direction > 0 && idx < parentTerminalWidget->count() - 1)) { | ||
216 | index = 0; | 191 | parentTerminalWidget->widget(idx + direction)->setFocus(Qt::OtherFocusReason); | ||
217 | } else { | | |||
218 | index++; | | |||
219 | } | 192 | } | ||
220 | | ||||
221 | setActiveContainer(_containers.at(index)); | | |||
222 | } | 193 | } | ||
223 | 194 | | |||
224 | void ViewSplitter::activatePreviousContainer() | 195 | void ViewSplitter::focusUp() | ||
225 | { | 196 | { | ||
226 | TabbedViewContainer *active = activeContainer(); | 197 | handleFocusDirection(Qt::Vertical, -1); | ||
227 | | ||||
228 | int index = _containers.indexOf(active); | | |||
229 | | ||||
230 | if (index == 0) { | | |||
231 | index = _containers.count() - 1; | | |||
232 | } else { | | |||
233 | index--; | | |||
234 | } | 198 | } | ||
235 | 199 | | |||
236 | setActiveContainer(_containers.at(index)); | 200 | void ViewSplitter::focusDown() | ||
201 | { | ||||
202 | handleFocusDirection(Qt::Vertical, +1); | ||||
237 | } | 203 | } | ||
238 | 204 | | |||
239 | void ViewSplitter::setActiveContainer(TabbedViewContainer *container) | 205 | void ViewSplitter::focusLeft() | ||
240 | { | 206 | { | ||
241 | QWidget *activeView = container->currentWidget(); | 207 | handleFocusDirection(Qt::Horizontal, -1); | ||
242 | | ||||
243 | if (activeView != nullptr) { | | |||
244 | activeView->setFocus(Qt::OtherFocusReason); | | |||
245 | } | | |||
246 | } | 208 | } | ||
hindenburg: try not to shadow another variable here | |||||
247 | 209 | | |||
248 | TabbedViewContainer *ViewSplitter::activeContainer() const | 210 | void ViewSplitter::focusRight() | ||
249 | { | 211 | { | ||
250 | if (QWidget *focusW = focusWidget()) { | 212 | handleFocusDirection(Qt::Horizontal, +1); | ||
251 | TabbedViewContainer *focusContainer = nullptr; | 213 | } | ||
252 | 214 | | |||
253 | while (focusW != nullptr) { | 215 | TerminalDisplay *ViewSplitter::activeTerminalDisplay() const | ||
254 | foreach (TabbedViewContainer *container, _containers) { | 216 | { | ||
255 | if (container == focusW) { | 217 | auto focusedWidget = qobject_cast<TerminalDisplay*>(focusWidget()); | ||
256 | focusContainer = container; | 218 | return focusedWidget ? focusedWidget : findChild<TerminalDisplay*>(); | ||
257 | break; | | |||
258 | } | 219 | } | ||
220 | | ||||
221 | void ViewSplitter::maximizeCurrentTerminal() | ||||
222 | { | ||||
223 | handleMinimizeMaximize(true); | ||||
259 | } | 224 | } | ||
260 | focusW = focusW->parentWidget(); | 225 | | ||
226 | void ViewSplitter::restoreOtherTerminals() | ||||
227 | { | ||||
228 | handleMinimizeMaximize(false); | ||||
261 | } | 229 | } | ||
262 | 230 | | |||
263 | if (focusContainer != nullptr) { | 231 | void ViewSplitter::handleMinimizeMaximize(bool maximize) | ||
264 | return focusContainer; | 232 | { | ||
233 | auto viewSplitter = getToplevelSplitter(); | ||||
234 | auto terminalDisplays = viewSplitter->findChildren<TerminalDisplay*>(); | ||||
235 | auto currentActiveTerminal = viewSplitter->activeTerminalDisplay(); | ||||
236 | auto method = maximize ? &QWidget::hide : &QWidget::show; | ||||
237 | for(auto terminal : terminalDisplays) { | ||||
238 | if (Q_LIKELY(currentActiveTerminal != terminal)) { | ||||
239 | (terminal->*method)(); | ||||
265 | } | 240 | } | ||
266 | } | 241 | } | ||
267 | | ||||
268 | QList<ViewSplitter *> splitters = findChildren<ViewSplitter *>(); | | |||
269 | | ||||
270 | if (!splitters.isEmpty()) { | | |||
271 | return splitters.last()->activeContainer(); | | |||
272 | } else { | | |||
273 | if (!_containers.isEmpty()) { | | |||
274 | return _containers.last(); | | |||
275 | } else { | | |||
276 | return nullptr; | | |||
277 | } | 242 | } | ||
243 | | ||||
244 | ViewSplitter *ViewSplitter::getToplevelSplitter() | ||||
245 | { | ||||
246 | ViewSplitter *current = this; | ||||
247 | while(qobject_cast<ViewSplitter*>(current->parentWidget())) { | ||||
248 | current = qobject_cast<ViewSplitter*>(current->parentWidget()); | ||||
278 | } | 249 | } | ||
250 | return current; | ||||
279 | } | 251 | } |
try not to shadow another variable here