1 /*
2  * SPDX-FileCopyrightText: 2014 Emmanuel Pescosta <emmanuelpescosta099@gmail.com>
3  * SPDX-FileCopyrightText: 2020 Felix Ernst <fe.a.ernst@gmail.com>
4  *
5  * SPDX-License-Identifier: GPL-2.0-or-later
6  */
7 
8 #ifndef DOLPHIN_TAB_PAGE_H
9 #define DOLPHIN_TAB_PAGE_H
10 
11 #include <QPointer>
12 #include <QUrl>
13 #include <QWidget>
14 #include <QSplitter>
15 
16 class DolphinNavigatorsWidgetAction;
17 class DolphinViewContainer;
18 class QVariantAnimation;
19 class KFileItemList;
20 class DolphinTabPageSplitter;
21 
22 enum Animated {
23     WithAnimation,
24     WithoutAnimation
25 };
26 
27 class DolphinTabPage : public QWidget
28 {
29     Q_OBJECT
30 
31 public:
32     explicit DolphinTabPage(const QUrl& primaryUrl, const QUrl& secondaryUrl = QUrl(), QWidget* parent = nullptr);
33 
34     /**
35      * @return True if primary view is the active view in this tab.
36      */
37     bool primaryViewActive() const;
38 
39     /**
40      * @return True if split view is enabled.
41      */
42     bool splitViewEnabled() const;
43 
44     /**
45      * Enables or disables the split view mode.
46      *
47      * @param enabled      If true, creates a secondary viewContainer in this tab.
48      *                     Otherwise deletes it.
49      * @param animated     Decides wether the effects of this method call should
50      *                     happen instantly or be transitioned to smoothly.
51      * @param secondaryUrl If \p enabled is true, the new viewContainer will be opened at this
52      *                     parameter. The default value will set the Url of the new viewContainer
53      *                     to be the same as the existing one.
54      */
55     void setSplitViewEnabled(bool enabled, Animated animated, const QUrl &secondaryUrl = QUrl());
56 
57     /**
58      * @return The primary view container.
59      */
60     DolphinViewContainer* primaryViewContainer() const;
61 
62     /**
63      * @return The secondary view container, can be 0 if split view is disabled.
64      */
65     DolphinViewContainer* secondaryViewContainer() const;
66 
67     /**
68      * @return DolphinViewContainer of the active view
69      */
70     DolphinViewContainer* activeViewContainer() const;
71 
72     /**
73      * Returns the selected items. The list is empty if no item has been
74      * selected.
75      */
76     KFileItemList selectedItems() const;
77 
78     /**
79      * Returns the number of selected items (this is faster than
80      * invoking selectedItems().count()).
81      */
82     int selectedItemsCount() const;
83 
84     /**
85      * Connects a navigatorsWidget to this. It will be connected to the DolphinViewContainers
86      * managed by this tab. For alignment purposes this will from now on notify the
87      * navigatorsWidget when this tab or its viewContainers are resized.
88      */
89     void connectNavigators(DolphinNavigatorsWidgetAction *navigatorsWidget);
90 
91     /**
92      * Makes it so this tab and its DolphinViewContainers aren't controlled by any
93      * UrlNavigators anymore.
94      */
95     void disconnectNavigators();
96 
97     void insertNavigatorsWidget(DolphinNavigatorsWidgetAction *navigatorsWidget);
98 
99     /**
100      * Marks the items indicated by \p urls to get selected after the
101      * directory DolphinView::url() has been loaded. Note that nothing
102      * gets selected if no loading of a directory has been triggered
103      * by DolphinView::setUrl() or DolphinView::reload().
104      */
105     void markUrlsAsSelected(const QList<QUrl> &urls);
106 
107     /**
108      * Marks the item indicated by \p url to be scrolled to and as the
109      * current item after directory DolphinView::url() has been loaded.
110      */
111     void markUrlAsCurrent(const QUrl& url);
112 
113     /**
114      * Refreshes the views of the main window by recreating them according to
115      * the given Dolphin settings.
116      */
117     void refreshViews();
118 
119     /**
120      * Saves all tab related properties (urls, splitter layout, ...).
121      *
122      * @return A byte-array which contains all properties.
123      */
124     QByteArray saveState() const;
125 
126     /**
127      * Restores all tab related properties (urls, splitter layout, ...) from
128      * the given \a state.
129      */
130     void restoreState(const QByteArray& state);
131 
132     /**
133      * Set whether the tab page is active
134      *
135      */
136     void setActive(bool active);
137 
138 Q_SIGNALS:
139     void activeViewChanged(DolphinViewContainer* viewContainer);
140     void activeViewUrlChanged(const QUrl& url);
141     void splitterMoved(int pos, int index);
142 
143 private Q_SLOTS:
144     /**
145      * Deletes all zombie viewContainers that were used for the animation
146      * and resets the minimum size of the others to a sane value.
147      */
148     void slotAnimationFinished();
149 
150     /**
151      * This method is called for every frame of the m_expandViewAnimation.
152      */
153     void slotAnimationValueChanged(const QVariant &value);
154 
155     /**
156      * Handles the view activated event.
157      *
158      * It sets the previous active view to inactive, updates the current
159      * active view type and triggers the activeViewChanged event.
160      */
161     void slotViewActivated();
162 
163     /**
164      * Handles the view url redirection event.
165      *
166      * It emits the activeViewUrlChanged signal with the url \a newUrl.
167      */
168     void slotViewUrlRedirection(const QUrl& oldUrl, const QUrl& newUrl);
169 
170     void switchActiveView();
171 
172 private:
173     /**
174      * Creates a new view container and does the default initialization.
175      */
176     DolphinViewContainer* createViewContainer(const QUrl& url) const;
177 
178     /**
179      * Starts an animation that transitions between split view mode states.
180      *
181      * One of the viewContainers is always being expanded when toggling so
182      * this method can animate both opening and closing of viewContainers.
183      * @param expandingContainer The container that will increase in size
184      *                           over the course of the animation.
185      */
186     void startExpandViewAnimation(DolphinViewContainer *expandingContainer);
187 
188 private:
189     DolphinTabPageSplitter *m_splitter;
190 
191     QPointer<DolphinNavigatorsWidgetAction> m_navigatorsWidget;
192     QPointer<DolphinViewContainer> m_primaryViewContainer;
193     QPointer<DolphinViewContainer> m_secondaryViewContainer;
194 
195     DolphinViewContainer *m_expandingContainer;
196     QPointer<QVariantAnimation> m_expandViewAnimation;
197 
198     bool m_primaryViewActive;
199     bool m_splitViewEnabled;
200     bool m_active;
201 };
202 
203 class DolphinTabPageSplitterHandle : public QSplitterHandle
204 {
205     Q_OBJECT
206 
207 public:
208     explicit DolphinTabPageSplitterHandle(Qt::Orientation orientation, QSplitter *parent);
209 
210 protected:
211     bool event(QEvent *event) override;
212 
213 private:
214     void resetSplitterSizes();
215 
216     // Sometimes QSplitterHandle doesn't receive MouseButtonDblClick event.
217     // We can detect that MouseButtonDblClick event should have been
218     // received if we receive two MouseButtonRelease events in a row.
219     bool m_mouseReleaseWasReceived;
220 };
221 
222 class DolphinTabPageSplitter : public QSplitter
223 {
224     Q_OBJECT
225 
226 public:
227     explicit DolphinTabPageSplitter(Qt::Orientation orientation, QWidget *parent);
228 
229 protected:
230     QSplitterHandle* createHandle() override;
231 };
232 
233 #endif // DOLPHIN_TAB_PAGE_H
234