1 /* ============================================================
2  *
3  * This file is a part of digiKam project
4  * https://www.digikam.org
5  *
6  * Date        : 2008-03-14
7  * Description : User interface for searches
8  *
9  * Copyright (C) 2008-2012 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
10  *
11  * This program is free software; you can redistribute it
12  * and/or modify it under the terms of the GNU General
13  * Public License as published by the Free Software Foundation;
14  * either version 2, or (at your option)
15  * any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * ============================================================ */
23 
24 #ifndef DIGIKAM_COMBOBOX_UTILITIES_H
25 #define DIGIKAM_COMBOBOX_UTILITIES_H
26 
27 // Qt includes
28 
29 #include <QLabel>
30 #include <QListView>
31 #include <QComboBox>
32 #include <QPersistentModelIndex>
33 #include <QLineEdit>
34 
35 // Local includes
36 
37 #include "digikam_export.h"
38 
39 class QVBoxLayout;
40 class QTreeView;
41 
42 namespace Digikam
43 {
44 
45 class DIGIKAM_EXPORT ProxyLineEdit : public QLineEdit
46 {
47     Q_OBJECT
48 
49 public:
50 
51     /**
52      * This class will not act as a QLineEdit at all,
53      * but present another widget (any kind of widget)
54      * instead in the space assigned to the QLineEdit.
55      * Use this class if you need to pass a QLineEdit but
56      * want actually to use a different widget.
57      */
58     explicit ProxyLineEdit(QWidget* const parent = nullptr);
59 
60     /**
61      * After constructing, set the actual widget here
62      */
63     virtual void setWidget(QWidget* widget);
64 
65     void setClearButtonShown(bool show);
66 
67 Q_SIGNALS:
68 
69     void signalClearButtonPressed();
70 
71 private Q_SLOTS:
72 
73     void slotTextChanged(const QString& text);
74 
75 protected:
76 
77     QSize minimumSizeHint() const                   override;
78     QSize sizeHint()        const                   override;
79 
80     void mousePressEvent(QMouseEvent* event)        override;
81     void mouseMoveEvent(QMouseEvent* event)         override;
82     void mouseReleaseEvent(QMouseEvent* event)      override;
83     void mouseDoubleClickEvent(QMouseEvent* event)  override;
84     void keyPressEvent(QKeyEvent* event)            override;
85     void focusInEvent(QFocusEvent* event)           override;
86     void focusOutEvent(QFocusEvent* event)          override;
87     void paintEvent(QPaintEvent* event)             override;
88     void dragEnterEvent(QDragEnterEvent* event)     override;
89     void dragMoveEvent(QDragMoveEvent* e)           override;
90     void dragLeaveEvent(QDragLeaveEvent* e)         override;
91     void dropEvent(QDropEvent* event)               override;
92     void changeEvent(QEvent* event)                 override;
93     void contextMenuEvent(QContextMenuEvent* event) override;
94     void inputMethodEvent(QInputMethodEvent* event) override;
95 
96 protected:
97 
98     QWidget*     m_widget;
99     QVBoxLayout* m_layout;
100 };
101 
102 // -------------------------------------------------------------------------
103 
104 class DIGIKAM_EXPORT ProxyClickLineEdit : public ProxyLineEdit
105 {
106     Q_OBJECT
107 
108 public:
109 
110     /**
111      * A ProxyLineEdit that emits leftClicked() on
112      * mouse press event.
113      * Press on the held widget will result in the signal
114      * if the widget does not accept() them.
115      */
116     explicit ProxyClickLineEdit(QWidget* const parent = nullptr);
117 
118 Q_SIGNALS:
119 
120     void leftClicked();
121 
122 protected:
123 
124     void mouseReleaseEvent(QMouseEvent* event) override;
125 };
126 
127 // -------------------------------------------------------------------------
128 
129 class DIGIKAM_EXPORT ModelIndexBasedComboBox : public QComboBox
130 {
131     Q_OBJECT
132 
133 public:
134 
135     /**
136      * QComboBox has a current index based on a single integer.
137      * This is not sufficient for more complex models.
138      * This class is a combo box that stores a current index
139      * based on QModelIndex.
140      */
141     explicit ModelIndexBasedComboBox(QWidget* const  parent = nullptr);
142 
143     QModelIndex currentIndex() const;
144     void setCurrentIndex(const QModelIndex& index);
145 
146     void hidePopup() override;
147     void showPopup() override;
148 
149 protected:
150 
151     QPersistentModelIndex m_currentIndex;
152 };
153 
154 // -------------------------------------------------------------------------
155 
156 class DIGIKAM_EXPORT StayPoppedUpComboBox : public ModelIndexBasedComboBox
157 {
158     Q_OBJECT
159 
160 public:
161 
162     /**
163      * This class provides an abstract QComboBox with a custom view
164      * (which is created by implementing subclasses)
165      * instead of the usual QListView.
166      * The Pop-up of the combo box will stay open after selecting an item;
167      * it will be closed by clicking outside, but not inside the widget.
168      * You need three steps:
169      * Construct the object, call setModel() with an appropriate
170      * QAbstractItemModel, then call installView() to replace
171      * the standard combo box view with a view.
172      */
173     explicit StayPoppedUpComboBox(QWidget* const parent = nullptr);
174 
175 protected:
176 
177     /**
178      * Replace the standard combo box list view with the given view.
179      * The view will be set as the view of the combo box
180      * (including re-parenting) and be stored in the m_view variable.
181      */
182     void installView(QAbstractItemView* view);
183 
184     /**
185      * Implement in subclass:
186      * Send the given event to the viewportEvent() method of m_view.
187      * This method is protected for a usual QAbstractItemView.
188      * You can override, pass a view, and call parent implementation.
189      * The existing view will be used. You must then also
190      * reimplement sendViewportEventToView.
191      */
192     virtual void sendViewportEventToView(QEvent* e) = 0;
193 
194     bool eventFilter(QObject* watched, QEvent* event) override;
195 
196 protected:
197 
198     QAbstractItemView* m_view;
199 };
200 
201 // -------------------------------------------------------------------------
202 
203 class DIGIKAM_EXPORT TreeViewComboBox : public StayPoppedUpComboBox
204 {
205     Q_OBJECT
206 
207 public:
208 
209     /**
210      * This class provides a QComboBox with a QTreeView
211      * instead of the usual QListView.
212      * You need three steps:
213      * Construct the object, call setModel() with an appropriate
214      * QAbstractItemModel, then call installView() to replace
215      * the standard combo box view with a QTreeView.
216      */
217     explicit TreeViewComboBox(QWidget* parent = nullptr);
218 
219     /**
220      * Replace the standard combo box list view with a QTreeView.
221      * Call this after installing an appropriate model.
222      */
223     virtual void installView(QAbstractItemView* view = nullptr);
224 
225     /**
226      * Returns the QTreeView of this class. Valid after installView() has been called
227      */
228     QTreeView* view() const;
229 
230 protected:
231 
232     void sendViewportEventToView(QEvent* e) override;
233 };
234 
235 // -------------------------------------------------------------------------
236 
237 class DIGIKAM_EXPORT ListViewComboBox : public StayPoppedUpComboBox
238 {
239     Q_OBJECT
240 
241 public:
242 
243     /**
244      * This class provides an implementation of a StayPoppedUpComboBox
245      * with a QListView. This is the standard view of a QComboBox,
246      * but in conjunction with StayPoppedUpComboBox some extra steps are needed.
247      * You need three steps:
248      * Construct the object, call setModel() with an appropriate
249      * QAbstractItemModel, then call installView().
250      */
251     explicit ListViewComboBox(QWidget* parent = nullptr);
252 
253     /**
254      * Returns the QTreeView of this class. Valid after installView() has been called.
255      */
256     QListView* view() const;
257 
258     /**
259      * Replace the standard combo box list view with a QTreeView.
260      * Call this after installing an appropriate model.
261      */
262     virtual void installView(QAbstractItemView* view = nullptr);
263 
264 protected:
265 
266     void sendViewportEventToView(QEvent* e) override;
267 };
268 
269 // -------------------------------------------------------------------------
270 
271 class DIGIKAM_EXPORT TreeViewLineEditComboBox : public TreeViewComboBox
272 {
273     Q_OBJECT
274 
275 public:
276 
277     /**
278      * This class provides a TreeViewComboBox
279      * with a read-only line edit.
280      * The text in the line edit can be adjusted. The combo box will
281      * open on a click on the line edit.
282      * You need three steps:
283      * Construct the object, call setModel() with an appropriate
284      * QAbstractItemModel, then call installView() to replace
285      * the standard combo box view with a QTreeView.
286      */
287     explicit TreeViewLineEditComboBox(QWidget* const parent = nullptr);
288 
289     /**
290      * Set the text of the line edit (the text that is visible
291      * if the popup is not opened).
292      * Applicable only for default installLineEdit() implementation.
293      */
294     void setLineEditText(const QString& text);
295 
296     void setLineEdit(QLineEdit* edit);
297 
298     /**
299      * Replace the standard combo box list view with a QTreeView.
300      * Call this after installing an appropriate model.
301      */
302     void installView(QAbstractItemView* view = nullptr) override;
303 
304 protected:
305 
306     /**
307      * Sets a line edit. Called by installView().
308      * The default implementation is described above.
309      * An empty implementation will keep the default QComboBox line edit.
310      */
311     virtual void installLineEdit();
312 
313 protected:
314 
315     QLineEdit* m_comboLineEdit;
316 };
317 
318 } // namespace Digikam
319 
320 #endif // DIGIKAM_COMBOBOX_UTILITIES_H
321