1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
|
/*
This file is part of the KDE project
SPDX-FileCopyrightText: 2020 Felix Ernst <[email protected]>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#ifndef DOLPHINNAVIGATORSWIDGETACTION_H
#define DOLPHINNAVIGATORSWIDGETACTION_H
#include "dolphinurlnavigator.h"
#include <QPointer>
#include <QSplitter>
#include <QTimer>
#include <QWidgetAction>
#include <memory>
class KXmlGuiWindow;
class QPushButton;
/**
* @brief QWidgetAction that allows to use DolphinUrlNavigators in a toolbar.
*
* This class is mainly a container that manages up to two DolphinUrlNavigator objects so they
* can be added to a toolbar. It also deals with alignment.
*
* The structure of the defaultWidget() of this QWidgetAction is as follows:
* - A QSplitter manages up to two sides which each correspond to one DolphinViewContainer.
* The secondary side only exists for split view and is created by
* createSecondaryUrlNavigator() when necessary.
* - Each side is a QWidget which I call NavigatorWidget with a QHBoxLayout.
* - Each NavigatorWidget consists an UrlNavigator, an emptyTrashButton, a
* networkFolderButton, and spacing.
* - Only the primary navigatorWidget has leading spacing. Both have trailing spacing.
* The spacing is there to align the UrlNavigator with its DolphinViewContainer.
*/
class DolphinNavigatorsWidgetAction : public QWidgetAction
{
Q_OBJECT
public:
DolphinNavigatorsWidgetAction(QWidget *parent = nullptr);
/**
* Adjusts the width of the spacings used to align the UrlNavigators with ViewContainers.
* This can only work nicely if up-to-date geometry of ViewContainers is cached so
* followViewContainersGeometry() has to have been called at least once before.
*/
void adjustSpacing();
/**
* The secondary UrlNavigator is only created on-demand. Such an action is not necessary
* for the primary UrlNavigator which is created preemptively.
*
* This method should preferably only be called when:
* - Split view is activated in the active tab
* OR
* - A switch to a tab that is already in split view mode is occurring
*/
void createSecondaryUrlNavigator();
/**
* Notify this widget of changes in geometry of the ViewContainers it tries to be
* aligned with.
*/
void followViewContainersGeometry(QWidget *primaryViewContainer, QWidget *secondaryViewContainer = nullptr);
bool isInToolbar() const;
/**
* @return the primary UrlNavigator.
*/
DolphinUrlNavigator *primaryUrlNavigator() const;
/**
* @return the secondary UrlNavigator and nullptr if it doesn't exist.
*/
DolphinUrlNavigator *secondaryUrlNavigator() const;
/**
* Change the visibility of the secondary UrlNavigator including spacing.
* @param visible Setting this to false will completely hide the secondary side of this
* WidgetAction's QSplitter making the QSplitter effectively disappear.
*/
void setSecondaryNavigatorVisible(bool visible);
/**
* Sets the background cosmetic of the location bar(s) visible or hidden.
* In frameless designs it's better to hide the background.
* @param enabled True for showing background cosmetic, false for hiding it.
*/
void setBackgroundEnabled(bool enabled);
protected:
/**
* There should always ever be one navigatorsWidget for this action so
* this method always returns the same widget and reparents it.
* You normally don't have to use this method directly because
* QWidgetAction::requestWidget() is used to obtain the navigatorsWidget
* and to steal it from wherever it was prior.
* @param parent the new parent of the navigatorsWidget.
*/
QWidget *createWidget(QWidget *parent) override;
/** @see QWidgetAction::deleteWidget() */
void deleteWidget(QWidget *widget) override;
private:
/**
* In Left-to-right languages the Primary side will be the left one.
*/
enum Side { Primary, Secondary };
/**
* Used to create the navigatorWidgets for both sides of the QSplitter.
*/
QWidget *createNavigatorWidget(Side side) const;
/**
* Used to retrieve the emptyTrashButtons for the navigatorWidgets on both sides.
*/
QPushButton *emptyTrashButton(Side side);
/**
* Creates a new empty trash button.
* @param urlNavigator Only when this UrlNavigator shows the trash directory
* will the button be visible.
* @param parent Aside from the usual QObject deletion mechanisms,
* this parameter influences the positioning of dialog windows
* pertaining to this trash button.
*/
QPushButton *newEmptyTrashButton(const DolphinUrlNavigator *urlNavigator, QWidget *parent) const;
/**
* Used to retrieve the networkFolderButtons for the navigatorWidgets on
* both sides.
*/
QPushButton *networkFolderButton(Side side);
/**
* Creates a new add "network folder" button.
* @param urlNavigator Only when this UrlNavigator shows the remote directory
* will the button be visible.
* @param parent The object that should be the button's parent.
*/
QPushButton *newNetworkFolderButton(const DolphinUrlNavigator *urlNavigator, QWidget *parent) const;
enum Position { Leading, Trailing };
/**
* Used to retrieve both the leading and trailing spacing for the navigatorWidgets
* on both sides. A secondary leading spacing does not exist.
*/
QWidget *spacing(Side side, Position position) const;
/**
* Sets this action's text depending on the amount of visible UrlNavigators.
*/
void updateText();
/**
* The defaultWidget() of this QWidgetAction.
*/
std::unique_ptr<QSplitter> m_splitter;
/**
* adjustSpacing() has to be called slightly later than when urlChanged is emitted.
* This timer bridges that time.
*/
std::unique_ptr<QTimer> m_adjustSpacingTimer;
/**
* Extracts the geometry information needed by adjustSpacing() from
* ViewContainers. They are also monitored for size changes which
* will lead to adjustSpacing() calls.
*/
class ViewGeometriesHelper : public QObject
{
public:
/**
* @param navigatorsWidget The QWidget of the navigatorsWidgetAction.
* @param navigatorsWidgetAction is only used to call adjustSpacing() whenever that is
* deemed necessary.
*/
ViewGeometriesHelper(QWidget *navigatorsWidget, DolphinNavigatorsWidgetAction *navigatorsWidgetAction);
/**
* Calls m_navigatorsWidgetAction::adjustSpacing() when a watched object is resized.
*/
bool eventFilter(QObject *watched, QEvent *event) override;
/**
* Sets the ViewContainers whose geometry is obtained when viewGeometries() is called.
*/
void setViewContainers(QWidget *primaryViewContainer, QWidget *secondaryViewContainer = nullptr);
struct Geometries {
int globalXOfNavigatorsWidget;
int globalXOfPrimary;
int widthOfPrimary;
int globalXOfSecondary;
int widthOfSecondary;
};
/**
* @return a Geometries struct that contains values adjustSpacing() requires.
*/
Geometries viewGeometries();
private:
QWidget *m_navigatorsWidget;
/** Is only used to call adjustSpacing() whenever that is deemed necessary. */
DolphinNavigatorsWidgetAction *m_navigatorsWidgetAction;
QPointer<QWidget> m_primaryViewContainer;
QPointer<QWidget> m_secondaryViewContainer;
};
ViewGeometriesHelper m_viewGeometriesHelper;
/**
* Used to check if the window has been resized.
* @see ViewGeometriesHelper::eventFilter() for why this is needed.
*/
int m_previousWindowWidth = -1;
};
#endif // DOLPHINNAVIGATORSWIDGETACTION_H
|