2 * SPDX-FileCopyrightText: 2014 Emmanuel Pescosta <emmanuelpescosta099@gmail.com>
4 * SPDX-License-Identifier: GPL-2.0-or-later
7 #include "dolphintabpage.h"
9 #include "dolphin_generalsettings.h"
10 #include "dolphinviewcontainer.h"
12 #include <QPropertyAnimation>
14 #include <QVBoxLayout>
16 DolphinTabPage::DolphinTabPage(const QUrl
&primaryUrl
, const QUrl
&secondaryUrl
, QWidget
* parent
) :
18 m_primaryViewActive(true),
19 m_splitViewEnabled(false),
22 QVBoxLayout
* layout
= new QVBoxLayout(this);
23 layout
->setSpacing(0);
24 layout
->setContentsMargins(0, 0, 0, 0);
26 m_splitter
= new QSplitter(Qt::Horizontal
, this);
27 m_splitter
->setChildrenCollapsible(false);
28 connect(m_splitter
, &QSplitter::splitterMoved
,
29 this, &DolphinTabPage::splitterMoved
);
30 layout
->addWidget(m_splitter
);
32 // Create a new primary view
33 m_primaryViewContainer
= createViewContainer(primaryUrl
);
34 connect(m_primaryViewContainer
->view(), &DolphinView::urlChanged
,
35 this, &DolphinTabPage::activeViewUrlChanged
);
36 connect(m_primaryViewContainer
->view(), &DolphinView::redirection
,
37 this, &DolphinTabPage::slotViewUrlRedirection
);
39 m_splitter
->addWidget(m_primaryViewContainer
);
40 m_primaryViewContainer
->installEventFilter(this);
41 m_primaryViewContainer
->show();
43 if (secondaryUrl
.isValid() || GeneralSettings::splitView()) {
44 // Provide a secondary view, if the given secondary url is valid or if the
45 // startup settings are set this way (use the url of the primary view).
46 m_splitViewEnabled
= true;
47 const QUrl
& url
= secondaryUrl
.isValid() ? secondaryUrl
: primaryUrl
;
48 m_secondaryViewContainer
= createViewContainer(url
);
49 m_splitter
->addWidget(m_secondaryViewContainer
);
50 m_secondaryViewContainer
->installEventFilter(this);
51 m_secondaryViewContainer
->show();
54 m_primaryViewContainer
->setActive(true);
57 bool DolphinTabPage::primaryViewActive() const
59 return m_primaryViewActive
;
62 bool DolphinTabPage::splitViewEnabled() const
64 return m_splitViewEnabled
;
67 void DolphinTabPage::setSplitViewEnabled(bool enabled
, const QUrl
&secondaryUrl
)
69 if (m_splitViewEnabled
!= enabled
) {
70 m_splitViewEnabled
= enabled
;
73 int splitterTotalWidth
= m_splitter
->width();
74 const QUrl
& url
= (secondaryUrl
.isEmpty()) ? m_primaryViewContainer
->url() : secondaryUrl
;
75 m_secondaryViewContainer
= createViewContainer(url
);
77 auto secondaryNavigator
= m_navigatorsWidget
->secondaryUrlNavigator();
78 if (!secondaryNavigator
) {
79 m_navigatorsWidget
->createSecondaryUrlNavigator();
80 secondaryNavigator
= m_navigatorsWidget
->secondaryUrlNavigator();
82 m_secondaryViewContainer
->connectUrlNavigator(secondaryNavigator
);
83 m_navigatorsWidget
->setSecondaryNavigatorVisible(true);
85 m_splitter
->addWidget(m_secondaryViewContainer
);
86 m_secondaryViewContainer
->installEventFilter(this);
87 m_secondaryViewContainer
->setActive(true);
90 m_splitter
->widget(1)->setMinimumWidth(1);
91 const QList
<int> splitterSizes
= {m_splitter
->width(), 0};
92 m_splitter
->setSizes(splitterSizes
);
94 // TODO: This is only here to test the robustness of DolphinNavigatorsWidgetAction! I still have to move it to another merge request!
95 m_splitViewAnimation
= new QVariantAnimation(m_splitter
);
96 m_splitViewAnimation
->setDuration(200); // TODO: where do I get the animation times from again?
97 m_splitViewAnimation
->setStartValue(splitterTotalWidth
);
98 m_splitViewAnimation
->setEndValue(splitterTotalWidth
/ 2);
99 m_splitViewAnimation
->setEasingCurve(QEasingCurve::OutCubic
);
101 connect(m_splitViewAnimation
, &QVariantAnimation::valueChanged
, [=]() {
102 if (m_splitter
->count() != 2) {
105 int value
= m_splitViewAnimation
->currentValue().toInt();
106 const QList
<int> splitterSizes
= {value
, m_splitter
->width() - value
};
107 m_splitter
->setSizes(splitterSizes
);
108 if (value
== m_splitViewAnimation
->endValue().toInt()) {
109 m_splitter
->widget(1)->setMinimumWidth(m_splitter
->widget(1)->minimumSizeHint().width());
112 m_splitViewAnimation
->start(QAbstractAnimation::DeleteWhenStopped
);
113 m_secondaryViewContainer
->show();
115 m_navigatorsWidget
->setSecondaryNavigatorVisible(false);
116 m_secondaryViewContainer
->disconnectUrlNavigator();
118 DolphinViewContainer
* view
;
119 if (GeneralSettings::closeActiveSplitView()) {
120 view
= activeViewContainer();
121 if (m_primaryViewActive
) {
122 m_primaryViewContainer
->disconnectUrlNavigator();
123 m_secondaryViewContainer
->connectUrlNavigator(
124 m_navigatorsWidget
->primaryUrlNavigator());
126 // If the primary view is active, we have to swap the pointers
127 // because the secondary view will be the new primary view.
128 qSwap(m_primaryViewContainer
, m_secondaryViewContainer
);
129 m_primaryViewActive
= false;
132 view
= m_primaryViewActive
? m_secondaryViewContainer
: m_primaryViewContainer
;
133 if (!m_primaryViewActive
) {
134 m_primaryViewContainer
->disconnectUrlNavigator();
135 m_secondaryViewContainer
->connectUrlNavigator(
136 m_navigatorsWidget
->primaryUrlNavigator());
138 // If the secondary view is active, we have to swap the pointers
139 // because the secondary view will be the new primary view.
140 qSwap(m_primaryViewContainer
, m_secondaryViewContainer
);
141 m_primaryViewActive
= true;
144 m_primaryViewContainer
->setActive(true);
147 if (m_splitViewAnimation
) {
148 delete m_splitViewAnimation
;
149 m_splitter
->widget(0)->setMinimumWidth(m_splitter
->widget(0)->minimumSizeHint().width());
155 DolphinViewContainer
* DolphinTabPage::primaryViewContainer() const
157 return m_primaryViewContainer
;
160 DolphinViewContainer
* DolphinTabPage::secondaryViewContainer() const
162 return m_secondaryViewContainer
;
165 DolphinViewContainer
* DolphinTabPage::activeViewContainer() const
167 return m_primaryViewActive
? m_primaryViewContainer
:
168 m_secondaryViewContainer
;
171 KFileItemList
DolphinTabPage::selectedItems() const
173 KFileItemList items
= m_primaryViewContainer
->view()->selectedItems();
174 if (m_splitViewEnabled
) {
175 items
+= m_secondaryViewContainer
->view()->selectedItems();
180 int DolphinTabPage::selectedItemsCount() const
182 int selectedItemsCount
= m_primaryViewContainer
->view()->selectedItemsCount();
183 if (m_splitViewEnabled
) {
184 selectedItemsCount
+= m_secondaryViewContainer
->view()->selectedItemsCount();
186 return selectedItemsCount
;
189 void DolphinTabPage::connectNavigators(DolphinNavigatorsWidgetAction
*navigatorsWidget
)
191 m_navigatorsWidget
= navigatorsWidget
;
192 auto primaryNavigator
= navigatorsWidget
->primaryUrlNavigator();
193 primaryNavigator
->setActive(m_primaryViewActive
);
194 m_primaryViewContainer
->connectUrlNavigator(primaryNavigator
);
195 if (m_splitViewEnabled
) {
196 auto secondaryNavigator
= navigatorsWidget
->secondaryUrlNavigator();
197 if (!secondaryNavigator
) {
198 navigatorsWidget
->createSecondaryUrlNavigator();
199 secondaryNavigator
= navigatorsWidget
->secondaryUrlNavigator();
201 secondaryNavigator
->setActive(!m_primaryViewActive
);
202 m_secondaryViewContainer
->connectUrlNavigator(secondaryNavigator
);
207 void DolphinTabPage::disconnectNavigators()
209 m_navigatorsWidget
= nullptr;
210 m_primaryViewContainer
->disconnectUrlNavigator();
211 if (m_splitViewEnabled
) {
212 m_secondaryViewContainer
->disconnectUrlNavigator();
216 bool DolphinTabPage::eventFilter(QObject */
* watched */
, QEvent
*event
)
218 if (event
->type() == QEvent::Resize
&& m_navigatorsWidget
) {
224 void DolphinTabPage::resizeNavigators() const
226 if (!m_splitViewEnabled
) {
227 m_navigatorsWidget
->followViewContainerGeometry(
228 m_primaryViewContainer
->mapToGlobal(QPoint(0,0)).x(),
229 m_primaryViewContainer
->width());
231 m_navigatorsWidget
->followViewContainersGeometry(
232 m_primaryViewContainer
->mapToGlobal(QPoint(0,0)).x(),
233 m_primaryViewContainer
->width(),
234 m_secondaryViewContainer
->mapToGlobal(QPoint(0,0)).x(),
235 m_secondaryViewContainer
->width());
239 void DolphinTabPage::markUrlsAsSelected(const QList
<QUrl
>& urls
)
241 m_primaryViewContainer
->view()->markUrlsAsSelected(urls
);
242 if (m_splitViewEnabled
) {
243 m_secondaryViewContainer
->view()->markUrlsAsSelected(urls
);
247 void DolphinTabPage::markUrlAsCurrent(const QUrl
& url
)
249 m_primaryViewContainer
->view()->markUrlAsCurrent(url
);
250 if (m_splitViewEnabled
) {
251 m_secondaryViewContainer
->view()->markUrlAsCurrent(url
);
255 void DolphinTabPage::refreshViews()
257 m_primaryViewContainer
->readSettings();
258 if (m_splitViewEnabled
) {
259 m_secondaryViewContainer
->readSettings();
263 QByteArray
DolphinTabPage::saveState() const
266 QDataStream
stream(&state
, QIODevice::WriteOnly
);
268 stream
<< quint32(2); // Tab state version
270 stream
<< m_splitViewEnabled
;
272 stream
<< m_primaryViewContainer
->url();
273 stream
<< m_primaryViewContainer
->urlNavigatorInternalWithHistory()->isUrlEditable();
274 m_primaryViewContainer
->view()->saveState(stream
);
276 if (m_splitViewEnabled
) {
277 stream
<< m_secondaryViewContainer
->url();
278 stream
<< m_secondaryViewContainer
->urlNavigatorInternalWithHistory()->isUrlEditable();
279 m_secondaryViewContainer
->view()->saveState(stream
);
282 stream
<< m_primaryViewActive
;
283 stream
<< m_splitter
->saveState();
288 void DolphinTabPage::restoreState(const QByteArray
& state
)
290 if (state
.isEmpty()) {
294 QByteArray sd
= state
;
295 QDataStream
stream(&sd
, QIODevice::ReadOnly
);
297 // Read the version number of the tab state and check if the version is supported.
301 // The version of the tab state isn't supported, we can't restore it.
305 bool isSplitViewEnabled
= false;
306 stream
>> isSplitViewEnabled
;
307 setSplitViewEnabled(isSplitViewEnabled
);
310 stream
>> primaryUrl
;
311 m_primaryViewContainer
->setUrl(primaryUrl
);
312 bool primaryUrlEditable
;
313 stream
>> primaryUrlEditable
;
314 m_primaryViewContainer
->urlNavigatorInternalWithHistory()->setUrlEditable(primaryUrlEditable
);
315 m_primaryViewContainer
->view()->restoreState(stream
);
317 if (isSplitViewEnabled
) {
319 stream
>> secondaryUrl
;
320 m_secondaryViewContainer
->setUrl(secondaryUrl
);
321 bool secondaryUrlEditable
;
322 stream
>> secondaryUrlEditable
;
323 m_secondaryViewContainer
->urlNavigatorInternalWithHistory()->setUrlEditable(secondaryUrlEditable
);
324 m_secondaryViewContainer
->view()->restoreState(stream
);
327 stream
>> m_primaryViewActive
;
328 if (m_primaryViewActive
) {
329 m_primaryViewContainer
->setActive(true);
330 m_navigatorsWidget
->primaryUrlNavigator()->setActive(true);
332 Q_ASSERT(m_splitViewEnabled
);
333 m_secondaryViewContainer
->setActive(true);
334 m_navigatorsWidget
->primaryUrlNavigator()->setActive(false);
337 if (m_splitViewAnimation
) {
338 delete m_splitViewAnimation
;
339 m_splitter
->widget(0)->setMinimumWidth(m_splitter
->widget(0)->minimumSizeHint().width());
341 QByteArray splitterState
;
342 stream
>> splitterState
;
343 m_splitter
->restoreState(splitterState
);
346 void DolphinTabPage::restoreStateV1(const QByteArray
& state
)
348 if (state
.isEmpty()) {
352 QByteArray sd
= state
;
353 QDataStream
stream(&sd
, QIODevice::ReadOnly
);
355 bool isSplitViewEnabled
= false;
356 stream
>> isSplitViewEnabled
;
357 setSplitViewEnabled(isSplitViewEnabled
);
360 stream
>> primaryUrl
;
361 m_primaryViewContainer
->setUrl(primaryUrl
);
362 bool primaryUrlEditable
;
363 stream
>> primaryUrlEditable
;
364 m_primaryViewContainer
->urlNavigatorInternalWithHistory()->setUrlEditable(primaryUrlEditable
);
366 if (isSplitViewEnabled
) {
368 stream
>> secondaryUrl
;
369 m_secondaryViewContainer
->setUrl(secondaryUrl
);
370 bool secondaryUrlEditable
;
371 stream
>> secondaryUrlEditable
;
372 m_secondaryViewContainer
->urlNavigatorInternalWithHistory()->setUrlEditable(secondaryUrlEditable
);
375 stream
>> m_primaryViewActive
;
376 if (m_primaryViewActive
) {
377 m_primaryViewContainer
->setActive(true);
379 Q_ASSERT(m_splitViewEnabled
);
380 m_secondaryViewContainer
->setActive(true);
383 QByteArray splitterState
;
384 stream
>> splitterState
;
385 m_splitter
->restoreState(splitterState
);
388 void DolphinTabPage::setActive(bool active
)
393 // we should bypass changing active view in split mode
394 m_active
= !m_splitViewEnabled
;
396 // we want view to fire activated when goes from false to true
397 activeViewContainer()->setActive(active
);
400 void DolphinTabPage::slotViewActivated()
402 const DolphinView
* oldActiveView
= activeViewContainer()->view();
404 // Set the view, which was active before, to inactive
405 // and update the active view type, if tab is active
407 if (m_splitViewEnabled
) {
408 activeViewContainer()->setActive(false);
409 m_primaryViewActive
= !m_primaryViewActive
;
411 m_primaryViewActive
= true;
412 if (m_secondaryViewContainer
) {
413 m_secondaryViewContainer
->setActive(false);
418 const DolphinView
* newActiveView
= activeViewContainer()->view();
420 if (newActiveView
== oldActiveView
) {
424 disconnect(oldActiveView
, &DolphinView::urlChanged
,
425 this, &DolphinTabPage::activeViewUrlChanged
);
426 disconnect(oldActiveView
, &DolphinView::redirection
,
427 this, &DolphinTabPage::slotViewUrlRedirection
);
428 connect(newActiveView
, &DolphinView::urlChanged
,
429 this, &DolphinTabPage::activeViewUrlChanged
);
430 connect(newActiveView
, &DolphinView::redirection
,
431 this, &DolphinTabPage::slotViewUrlRedirection
);
432 Q_EMIT
activeViewChanged(activeViewContainer());
433 Q_EMIT
activeViewUrlChanged(activeViewContainer()->url());
436 void DolphinTabPage::slotViewUrlRedirection(const QUrl
& oldUrl
, const QUrl
& newUrl
)
440 Q_EMIT
activeViewUrlChanged(newUrl
);
443 void DolphinTabPage::switchActiveView()
445 if (!m_splitViewEnabled
) {
448 if (m_primaryViewActive
) {
449 m_secondaryViewContainer
->setActive(true);
451 m_primaryViewContainer
->setActive(true);
455 DolphinViewContainer
* DolphinTabPage::createViewContainer(const QUrl
& url
) const
457 DolphinViewContainer
* container
= new DolphinViewContainer(url
, m_splitter
);
458 container
->setActive(false);
460 const DolphinView
* view
= container
->view();
461 connect(view
, &DolphinView::activated
,
462 this, &DolphinTabPage::slotViewActivated
);
464 connect(view
, &DolphinView::toggleActiveViewRequested
,
465 this, &DolphinTabPage::switchActiveView
);