]> cloud.milkyroute.net Git - dolphin.git/blob - src/dolphintabpage.cpp
d196508a8756e71a9e44054f22a59bb1dd9d6e92
[dolphin.git] / src / dolphintabpage.cpp
1 /*
2 * SPDX-FileCopyrightText: 2014 Emmanuel Pescosta <emmanuelpescosta099@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7 #include "dolphintabpage.h"
8
9 #include "dolphin_generalsettings.h"
10 #include "dolphinviewcontainer.h"
11
12 #include <QSplitter>
13 #include <QVBoxLayout>
14
15 DolphinTabPage::DolphinTabPage(const QUrl &primaryUrl, const QUrl &secondaryUrl, QWidget* parent) :
16 QWidget(parent),
17 m_primaryViewActive(true),
18 m_splitViewEnabled(false),
19 m_active(true)
20 {
21 QVBoxLayout* layout = new QVBoxLayout(this);
22 layout->setSpacing(0);
23 layout->setContentsMargins(0, 0, 0, 0);
24
25 m_splitter = new QSplitter(Qt::Horizontal, this);
26 m_splitter->setChildrenCollapsible(false);
27 connect(m_splitter, &QSplitter::splitterMoved,
28 this, &DolphinTabPage::splitterMoved);
29 layout->addWidget(m_splitter);
30
31 // Create a new primary view
32 m_primaryViewContainer = createViewContainer(primaryUrl);
33 connect(m_primaryViewContainer->view(), &DolphinView::urlChanged,
34 this, &DolphinTabPage::activeViewUrlChanged);
35 connect(m_primaryViewContainer->view(), &DolphinView::redirection,
36 this, &DolphinTabPage::slotViewUrlRedirection);
37
38 m_splitter->addWidget(m_primaryViewContainer);
39 m_primaryViewContainer->installEventFilter(this);
40 m_primaryViewContainer->show();
41
42 if (secondaryUrl.isValid() || GeneralSettings::splitView()) {
43 // Provide a secondary view, if the given secondary url is valid or if the
44 // startup settings are set this way (use the url of the primary view).
45 m_splitViewEnabled = true;
46 const QUrl& url = secondaryUrl.isValid() ? secondaryUrl : primaryUrl;
47 m_secondaryViewContainer = createViewContainer(url);
48 m_splitter->addWidget(m_secondaryViewContainer);
49 m_secondaryViewContainer->installEventFilter(this);
50 m_secondaryViewContainer->show();
51 }
52
53 m_primaryViewContainer->setActive(true);
54 }
55
56 bool DolphinTabPage::primaryViewActive() const
57 {
58 return m_primaryViewActive;
59 }
60
61 bool DolphinTabPage::splitViewEnabled() const
62 {
63 return m_splitViewEnabled;
64 }
65
66 void DolphinTabPage::setSplitViewEnabled(bool enabled, const QUrl &secondaryUrl)
67 {
68 if (m_splitViewEnabled != enabled) {
69 m_splitViewEnabled = enabled;
70
71 if (enabled) {
72 const QUrl& url = (secondaryUrl.isEmpty()) ? m_primaryViewContainer->url() : secondaryUrl;
73 m_secondaryViewContainer = createViewContainer(url);
74
75 auto secondaryNavigator = m_navigatorsWidget->secondaryUrlNavigator();
76 if (!secondaryNavigator) {
77 m_navigatorsWidget->createSecondaryUrlNavigator();
78 secondaryNavigator = m_navigatorsWidget->secondaryUrlNavigator();
79 }
80 m_secondaryViewContainer->connectUrlNavigator(secondaryNavigator);
81 m_navigatorsWidget->setSecondaryNavigatorVisible(true);
82
83 m_splitter->addWidget(m_secondaryViewContainer);
84 m_secondaryViewContainer->installEventFilter(this);
85 m_secondaryViewContainer->show();
86 m_secondaryViewContainer->setActive(true);
87 } else {
88 m_navigatorsWidget->setSecondaryNavigatorVisible(false);
89 m_secondaryViewContainer->disconnectUrlNavigator();
90
91 DolphinViewContainer* view;
92 if (GeneralSettings::closeActiveSplitView()) {
93 view = activeViewContainer();
94 if (m_primaryViewActive) {
95 m_primaryViewContainer->disconnectUrlNavigator();
96 m_secondaryViewContainer->connectUrlNavigator(
97 m_navigatorsWidget->primaryUrlNavigator());
98
99 // If the primary view is active, we have to swap the pointers
100 // because the secondary view will be the new primary view.
101 qSwap(m_primaryViewContainer, m_secondaryViewContainer);
102 m_primaryViewActive = false;
103 }
104 } else {
105 view = m_primaryViewActive ? m_secondaryViewContainer : m_primaryViewContainer;
106 if (!m_primaryViewActive) {
107 m_primaryViewContainer->disconnectUrlNavigator();
108 m_secondaryViewContainer->connectUrlNavigator(
109 m_navigatorsWidget->primaryUrlNavigator());
110
111 // If the secondary view is active, we have to swap the pointers
112 // because the secondary view will be the new primary view.
113 qSwap(m_primaryViewContainer, m_secondaryViewContainer);
114 m_primaryViewActive = true;
115 }
116 }
117 m_primaryViewContainer->setActive(true);
118 view->close();
119 view->deleteLater();
120 }
121 }
122 }
123
124 DolphinViewContainer* DolphinTabPage::primaryViewContainer() const
125 {
126 return m_primaryViewContainer;
127 }
128
129 DolphinViewContainer* DolphinTabPage::secondaryViewContainer() const
130 {
131 return m_secondaryViewContainer;
132 }
133
134 DolphinViewContainer* DolphinTabPage::activeViewContainer() const
135 {
136 return m_primaryViewActive ? m_primaryViewContainer :
137 m_secondaryViewContainer;
138 }
139
140 KFileItemList DolphinTabPage::selectedItems() const
141 {
142 KFileItemList items = m_primaryViewContainer->view()->selectedItems();
143 if (m_splitViewEnabled) {
144 items += m_secondaryViewContainer->view()->selectedItems();
145 }
146 return items;
147 }
148
149 int DolphinTabPage::selectedItemsCount() const
150 {
151 int selectedItemsCount = m_primaryViewContainer->view()->selectedItemsCount();
152 if (m_splitViewEnabled) {
153 selectedItemsCount += m_secondaryViewContainer->view()->selectedItemsCount();
154 }
155 return selectedItemsCount;
156 }
157
158 void DolphinTabPage::connectNavigators(DolphinNavigatorsWidgetAction *navigatorsWidget)
159 {
160 m_navigatorsWidget = navigatorsWidget;
161 auto primaryNavigator = navigatorsWidget->primaryUrlNavigator();
162 primaryNavigator->setActive(m_primaryViewActive);
163 m_primaryViewContainer->connectUrlNavigator(primaryNavigator);
164 if (m_splitViewEnabled) {
165 auto secondaryNavigator = navigatorsWidget->secondaryUrlNavigator();
166 secondaryNavigator->setActive(!m_primaryViewActive);
167 m_secondaryViewContainer->connectUrlNavigator(secondaryNavigator);
168 }
169 resizeNavigators();
170 }
171
172 void DolphinTabPage::disconnectNavigators()
173 {
174 m_navigatorsWidget = nullptr;
175 m_primaryViewContainer->disconnectUrlNavigator();
176 if (m_splitViewEnabled) {
177 m_secondaryViewContainer->disconnectUrlNavigator();
178 }
179 }
180
181 bool DolphinTabPage::eventFilter(QObject */* watched */, QEvent *event)
182 {
183 if (event->type() == QEvent::Resize && m_navigatorsWidget) {
184 resizeNavigators();
185 }
186 return false;
187 }
188
189 void DolphinTabPage::resizeNavigators() const
190 {
191 if (!m_splitViewEnabled) {
192 m_navigatorsWidget->followViewContainerGeometry(
193 m_primaryViewContainer->mapToGlobal(QPoint(0,0)).x(),
194 m_primaryViewContainer->width());
195 } else {
196 m_navigatorsWidget->followViewContainersGeometry(
197 m_primaryViewContainer->mapToGlobal(QPoint(0,0)).x(),
198 m_primaryViewContainer->width(),
199 m_secondaryViewContainer->mapToGlobal(QPoint(0,0)).x(),
200 m_secondaryViewContainer->width());
201 }
202 }
203
204 void DolphinTabPage::markUrlsAsSelected(const QList<QUrl>& urls)
205 {
206 m_primaryViewContainer->view()->markUrlsAsSelected(urls);
207 if (m_splitViewEnabled) {
208 m_secondaryViewContainer->view()->markUrlsAsSelected(urls);
209 }
210 }
211
212 void DolphinTabPage::markUrlAsCurrent(const QUrl& url)
213 {
214 m_primaryViewContainer->view()->markUrlAsCurrent(url);
215 if (m_splitViewEnabled) {
216 m_secondaryViewContainer->view()->markUrlAsCurrent(url);
217 }
218 }
219
220 void DolphinTabPage::refreshViews()
221 {
222 m_primaryViewContainer->readSettings();
223 if (m_splitViewEnabled) {
224 m_secondaryViewContainer->readSettings();
225 }
226 }
227
228 QByteArray DolphinTabPage::saveState() const
229 {
230 QByteArray state;
231 QDataStream stream(&state, QIODevice::WriteOnly);
232
233 stream << quint32(2); // Tab state version
234
235 stream << m_splitViewEnabled;
236
237 stream << m_primaryViewContainer->url();
238 stream << m_primaryViewContainer->urlNavigatorInternalWithHistory()->isUrlEditable();
239 m_primaryViewContainer->view()->saveState(stream);
240
241 if (m_splitViewEnabled) {
242 stream << m_secondaryViewContainer->url();
243 stream << m_secondaryViewContainer->urlNavigatorInternalWithHistory()->isUrlEditable();
244 m_secondaryViewContainer->view()->saveState(stream);
245 }
246
247 stream << m_primaryViewActive;
248 stream << m_splitter->saveState();
249
250 return state;
251 }
252
253 void DolphinTabPage::restoreState(const QByteArray& state)
254 {
255 if (state.isEmpty()) {
256 return;
257 }
258
259 QByteArray sd = state;
260 QDataStream stream(&sd, QIODevice::ReadOnly);
261
262 // Read the version number of the tab state and check if the version is supported.
263 quint32 version = 0;
264 stream >> version;
265 if (version != 2) {
266 // The version of the tab state isn't supported, we can't restore it.
267 return;
268 }
269
270 bool isSplitViewEnabled = false;
271 stream >> isSplitViewEnabled;
272 setSplitViewEnabled(isSplitViewEnabled);
273
274 QUrl primaryUrl;
275 stream >> primaryUrl;
276 m_primaryViewContainer->setUrl(primaryUrl);
277 bool primaryUrlEditable;
278 stream >> primaryUrlEditable;
279 m_primaryViewContainer->urlNavigatorInternalWithHistory()->setUrlEditable(primaryUrlEditable);
280 m_primaryViewContainer->view()->restoreState(stream);
281
282 if (isSplitViewEnabled) {
283 QUrl secondaryUrl;
284 stream >> secondaryUrl;
285 m_secondaryViewContainer->setUrl(secondaryUrl);
286 bool secondaryUrlEditable;
287 stream >> secondaryUrlEditable;
288 m_secondaryViewContainer->urlNavigatorInternalWithHistory()->setUrlEditable(secondaryUrlEditable);
289 m_secondaryViewContainer->view()->restoreState(stream);
290 }
291
292 stream >> m_primaryViewActive;
293 if (m_primaryViewActive) {
294 m_primaryViewContainer->setActive(true);
295 m_navigatorsWidget->primaryUrlNavigator()->setActive(true);
296 } else {
297 Q_ASSERT(m_splitViewEnabled);
298 m_secondaryViewContainer->setActive(true);
299 m_navigatorsWidget->primaryUrlNavigator()->setActive(false);
300 }
301
302 QByteArray splitterState;
303 stream >> splitterState;
304 m_splitter->restoreState(splitterState);
305 }
306
307 void DolphinTabPage::restoreStateV1(const QByteArray& state)
308 {
309 if (state.isEmpty()) {
310 return;
311 }
312
313 QByteArray sd = state;
314 QDataStream stream(&sd, QIODevice::ReadOnly);
315
316 bool isSplitViewEnabled = false;
317 stream >> isSplitViewEnabled;
318 setSplitViewEnabled(isSplitViewEnabled);
319
320 QUrl primaryUrl;
321 stream >> primaryUrl;
322 m_primaryViewContainer->setUrl(primaryUrl);
323 bool primaryUrlEditable;
324 stream >> primaryUrlEditable;
325 m_primaryViewContainer->urlNavigatorInternalWithHistory()->setUrlEditable(primaryUrlEditable);
326
327 if (isSplitViewEnabled) {
328 QUrl secondaryUrl;
329 stream >> secondaryUrl;
330 m_secondaryViewContainer->setUrl(secondaryUrl);
331 bool secondaryUrlEditable;
332 stream >> secondaryUrlEditable;
333 m_secondaryViewContainer->urlNavigatorInternalWithHistory()->setUrlEditable(secondaryUrlEditable);
334 }
335
336 stream >> m_primaryViewActive;
337 if (m_primaryViewActive) {
338 m_primaryViewContainer->setActive(true);
339 } else {
340 Q_ASSERT(m_splitViewEnabled);
341 m_secondaryViewContainer->setActive(true);
342 }
343
344 QByteArray splitterState;
345 stream >> splitterState;
346 m_splitter->restoreState(splitterState);
347 }
348
349 void DolphinTabPage::setActive(bool active)
350 {
351 if (active) {
352 m_active = active;
353 } else {
354 // we should bypass changing active view in split mode
355 m_active = !m_splitViewEnabled;
356 }
357 // we want view to fire activated when goes from false to true
358 activeViewContainer()->setActive(active);
359 }
360
361 void DolphinTabPage::slotViewActivated()
362 {
363 const DolphinView* oldActiveView = activeViewContainer()->view();
364
365 // Set the view, which was active before, to inactive
366 // and update the active view type, if tab is active
367 if (m_active) {
368 if (m_splitViewEnabled) {
369 activeViewContainer()->setActive(false);
370 m_primaryViewActive = !m_primaryViewActive;
371 } else {
372 m_primaryViewActive = true;
373 if (m_secondaryViewContainer) {
374 m_secondaryViewContainer->setActive(false);
375 }
376 }
377 }
378
379 const DolphinView* newActiveView = activeViewContainer()->view();
380
381 if (newActiveView == oldActiveView) {
382 return;
383 }
384
385 disconnect(oldActiveView, &DolphinView::urlChanged,
386 this, &DolphinTabPage::activeViewUrlChanged);
387 disconnect(oldActiveView, &DolphinView::redirection,
388 this, &DolphinTabPage::slotViewUrlRedirection);
389 connect(newActiveView, &DolphinView::urlChanged,
390 this, &DolphinTabPage::activeViewUrlChanged);
391 connect(newActiveView, &DolphinView::redirection,
392 this, &DolphinTabPage::slotViewUrlRedirection);
393 Q_EMIT activeViewChanged(activeViewContainer());
394 Q_EMIT activeViewUrlChanged(activeViewContainer()->url());
395 }
396
397 void DolphinTabPage::slotViewUrlRedirection(const QUrl& oldUrl, const QUrl& newUrl)
398 {
399 Q_UNUSED(oldUrl)
400
401 Q_EMIT activeViewUrlChanged(newUrl);
402 }
403
404 void DolphinTabPage::switchActiveView()
405 {
406 if (!m_splitViewEnabled) {
407 return;
408 }
409 if (m_primaryViewActive) {
410 m_secondaryViewContainer->setActive(true);
411 } else {
412 m_primaryViewContainer->setActive(true);
413 }
414 }
415
416 DolphinViewContainer* DolphinTabPage::createViewContainer(const QUrl& url) const
417 {
418 DolphinViewContainer* container = new DolphinViewContainer(url, m_splitter);
419 container->setActive(false);
420
421 const DolphinView* view = container->view();
422 connect(view, &DolphinView::activated,
423 this, &DolphinTabPage::slotViewActivated);
424
425 connect(view, &DolphinView::toggleActiveViewRequested,
426 this, &DolphinTabPage::switchActiveView);
427
428 return container;
429 }