]> cloud.milkyroute.net Git - dolphin.git/blob - src/dolphintabpage.cpp
Allow folder creation on desktop via F10 shortcut
[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 m_primaryViewContainer->connectUrlNavigator(primaryNavigator);
163 if (m_splitViewEnabled) {
164 auto secondaryNavigator = navigatorsWidget->secondaryUrlNavigator();
165 m_secondaryViewContainer->connectUrlNavigator(secondaryNavigator);
166 }
167 resizeNavigators();
168 }
169
170 void DolphinTabPage::disconnectNavigators()
171 {
172 m_navigatorsWidget = nullptr;
173 m_primaryViewContainer->disconnectUrlNavigator();
174 if (m_splitViewEnabled) {
175 m_secondaryViewContainer->disconnectUrlNavigator();
176 }
177 }
178
179 bool DolphinTabPage::eventFilter(QObject *watched, QEvent *event)
180 {
181 if (event->type() == QEvent::Resize && m_navigatorsWidget) {
182 resizeNavigators();
183 return false;
184 }
185 return QWidget::eventFilter(watched, event);
186 }
187
188 void DolphinTabPage::resizeNavigators() const
189 {
190 if (!m_splitViewEnabled) {
191 m_navigatorsWidget->followViewContainerGeometry(
192 m_primaryViewContainer->mapToGlobal(QPoint(0,0)).x(),
193 m_primaryViewContainer->width());
194 } else {
195 m_navigatorsWidget->followViewContainersGeometry(
196 m_primaryViewContainer->mapToGlobal(QPoint(0,0)).x(),
197 m_primaryViewContainer->width(),
198 m_secondaryViewContainer->mapToGlobal(QPoint(0,0)).x(),
199 m_secondaryViewContainer->width());
200 }
201 }
202
203 void DolphinTabPage::markUrlsAsSelected(const QList<QUrl>& urls)
204 {
205 m_primaryViewContainer->view()->markUrlsAsSelected(urls);
206 if (m_splitViewEnabled) {
207 m_secondaryViewContainer->view()->markUrlsAsSelected(urls);
208 }
209 }
210
211 void DolphinTabPage::markUrlAsCurrent(const QUrl& url)
212 {
213 m_primaryViewContainer->view()->markUrlAsCurrent(url);
214 if (m_splitViewEnabled) {
215 m_secondaryViewContainer->view()->markUrlAsCurrent(url);
216 }
217 }
218
219 void DolphinTabPage::refreshViews()
220 {
221 m_primaryViewContainer->readSettings();
222 if (m_splitViewEnabled) {
223 m_secondaryViewContainer->readSettings();
224 }
225 }
226
227 QByteArray DolphinTabPage::saveState() const
228 {
229 QByteArray state;
230 QDataStream stream(&state, QIODevice::WriteOnly);
231
232 stream << quint32(2); // Tab state version
233
234 stream << m_splitViewEnabled;
235
236 stream << m_primaryViewContainer->url();
237 stream << m_primaryViewContainer->urlNavigatorInternalWithHistory()->isUrlEditable();
238 m_primaryViewContainer->view()->saveState(stream);
239
240 if (m_splitViewEnabled) {
241 stream << m_secondaryViewContainer->url();
242 stream << m_secondaryViewContainer->urlNavigatorInternalWithHistory()->isUrlEditable();
243 m_secondaryViewContainer->view()->saveState(stream);
244 }
245
246 stream << m_primaryViewActive;
247 stream << m_splitter->saveState();
248
249 return state;
250 }
251
252 void DolphinTabPage::restoreState(const QByteArray& state)
253 {
254 if (state.isEmpty()) {
255 return;
256 }
257
258 QByteArray sd = state;
259 QDataStream stream(&sd, QIODevice::ReadOnly);
260
261 // Read the version number of the tab state and check if the version is supported.
262 quint32 version = 0;
263 stream >> version;
264 if (version != 2) {
265 // The version of the tab state isn't supported, we can't restore it.
266 return;
267 }
268
269 bool isSplitViewEnabled = false;
270 stream >> isSplitViewEnabled;
271 setSplitViewEnabled(isSplitViewEnabled);
272
273 QUrl primaryUrl;
274 stream >> primaryUrl;
275 m_primaryViewContainer->setUrl(primaryUrl);
276 bool primaryUrlEditable;
277 stream >> primaryUrlEditable;
278 m_primaryViewContainer->urlNavigatorInternalWithHistory()->setUrlEditable(primaryUrlEditable);
279 m_primaryViewContainer->view()->restoreState(stream);
280
281 if (isSplitViewEnabled) {
282 QUrl secondaryUrl;
283 stream >> secondaryUrl;
284 m_secondaryViewContainer->setUrl(secondaryUrl);
285 bool secondaryUrlEditable;
286 stream >> secondaryUrlEditable;
287 m_secondaryViewContainer->urlNavigatorInternalWithHistory()->setUrlEditable(secondaryUrlEditable);
288 m_secondaryViewContainer->view()->restoreState(stream);
289 }
290
291 stream >> m_primaryViewActive;
292 if (m_primaryViewActive) {
293 m_primaryViewContainer->setActive(true);
294 } else {
295 Q_ASSERT(m_splitViewEnabled);
296 m_secondaryViewContainer->setActive(true);
297 }
298
299 QByteArray splitterState;
300 stream >> splitterState;
301 m_splitter->restoreState(splitterState);
302 }
303
304 void DolphinTabPage::restoreStateV1(const QByteArray& state)
305 {
306 if (state.isEmpty()) {
307 return;
308 }
309
310 QByteArray sd = state;
311 QDataStream stream(&sd, QIODevice::ReadOnly);
312
313 bool isSplitViewEnabled = false;
314 stream >> isSplitViewEnabled;
315 setSplitViewEnabled(isSplitViewEnabled);
316
317 QUrl primaryUrl;
318 stream >> primaryUrl;
319 m_primaryViewContainer->setUrl(primaryUrl);
320 bool primaryUrlEditable;
321 stream >> primaryUrlEditable;
322 m_primaryViewContainer->urlNavigatorInternalWithHistory()->setUrlEditable(primaryUrlEditable);
323
324 if (isSplitViewEnabled) {
325 QUrl secondaryUrl;
326 stream >> secondaryUrl;
327 m_secondaryViewContainer->setUrl(secondaryUrl);
328 bool secondaryUrlEditable;
329 stream >> secondaryUrlEditable;
330 m_secondaryViewContainer->urlNavigatorInternalWithHistory()->setUrlEditable(secondaryUrlEditable);
331 }
332
333 stream >> m_primaryViewActive;
334 if (m_primaryViewActive) {
335 m_primaryViewContainer->setActive(true);
336 } else {
337 Q_ASSERT(m_splitViewEnabled);
338 m_secondaryViewContainer->setActive(true);
339 }
340
341 QByteArray splitterState;
342 stream >> splitterState;
343 m_splitter->restoreState(splitterState);
344 }
345
346 void DolphinTabPage::setActive(bool active)
347 {
348 if (active) {
349 m_active = active;
350 } else {
351 // we should bypass changing active view in split mode
352 m_active = !m_splitViewEnabled;
353 }
354 // we want view to fire activated when goes from false to true
355 activeViewContainer()->setActive(active);
356 }
357
358 void DolphinTabPage::slotViewActivated()
359 {
360 const DolphinView* oldActiveView = activeViewContainer()->view();
361
362 // Set the view, which was active before, to inactive
363 // and update the active view type, if tab is active
364 if (m_active) {
365 if (m_splitViewEnabled) {
366 activeViewContainer()->setActive(false);
367 m_primaryViewActive = !m_primaryViewActive;
368 } else {
369 m_primaryViewActive = true;
370 if (m_secondaryViewContainer) {
371 m_secondaryViewContainer->setActive(false);
372 }
373 }
374 }
375
376 const DolphinView* newActiveView = activeViewContainer()->view();
377
378 if (newActiveView == oldActiveView) {
379 return;
380 }
381
382 disconnect(oldActiveView, &DolphinView::urlChanged,
383 this, &DolphinTabPage::activeViewUrlChanged);
384 disconnect(oldActiveView, &DolphinView::redirection,
385 this, &DolphinTabPage::slotViewUrlRedirection);
386 connect(newActiveView, &DolphinView::urlChanged,
387 this, &DolphinTabPage::activeViewUrlChanged);
388 connect(newActiveView, &DolphinView::redirection,
389 this, &DolphinTabPage::slotViewUrlRedirection);
390 Q_EMIT activeViewChanged(activeViewContainer());
391 Q_EMIT activeViewUrlChanged(activeViewContainer()->url());
392 }
393
394 void DolphinTabPage::slotViewUrlRedirection(const QUrl& oldUrl, const QUrl& newUrl)
395 {
396 Q_UNUSED(oldUrl)
397
398 Q_EMIT activeViewUrlChanged(newUrl);
399 }
400
401 void DolphinTabPage::switchActiveView()
402 {
403 if (!m_splitViewEnabled) {
404 return;
405 }
406 if (m_primaryViewActive) {
407 m_secondaryViewContainer->setActive(true);
408 } else {
409 m_primaryViewContainer->setActive(true);
410 }
411 }
412
413 DolphinViewContainer* DolphinTabPage::createViewContainer(const QUrl& url) const
414 {
415 DolphinViewContainer* container = new DolphinViewContainer(url, m_splitter);
416 container->setActive(false);
417
418 const DolphinView* view = container->view();
419 connect(view, &DolphinView::activated,
420 this, &DolphinTabPage::slotViewActivated);
421
422 connect(view, &DolphinView::toggleActiveViewRequested,
423 this, &DolphinTabPage::switchActiveView);
424
425 return container;
426 }