1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the demonstration applications of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL21$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** $QT_END_LICENSE$
31 **
32 ****************************************************************************/
33
34 #include "modelmenu.h"
35
36 #include <QtCore/QAbstractItemModel>
37 #include <qdebug.h>
38
ModelMenu(QWidget * parent)39 ModelMenu::ModelMenu(QWidget * parent)
40 : QMenu(parent)
41 , m_maxRows(7)
42 , m_firstSeparator(-1)
43 , m_maxWidth(-1)
44 , m_hoverRole(0)
45 , m_separatorRole(0)
46 , m_model(0)
47 {
48 connect(this, SIGNAL(aboutToShow()), this, SLOT(aboutToShow()));
49 }
50
prePopulated()51 bool ModelMenu::prePopulated()
52 {
53 return false;
54 }
55
postPopulated()56 void ModelMenu::postPopulated()
57 {
58 }
59
setModel(QAbstractItemModel * model)60 void ModelMenu::setModel(QAbstractItemModel *model)
61 {
62 m_model = model;
63 }
64
model() const65 QAbstractItemModel *ModelMenu::model() const
66 {
67 return m_model;
68 }
69
setMaxRows(int max)70 void ModelMenu::setMaxRows(int max)
71 {
72 m_maxRows = max;
73 }
74
maxRows() const75 int ModelMenu::maxRows() const
76 {
77 return m_maxRows;
78 }
79
setFirstSeparator(int offset)80 void ModelMenu::setFirstSeparator(int offset)
81 {
82 m_firstSeparator = offset;
83 }
84
firstSeparator() const85 int ModelMenu::firstSeparator() const
86 {
87 return m_firstSeparator;
88 }
89
setRootIndex(const QModelIndex & index)90 void ModelMenu::setRootIndex(const QModelIndex &index)
91 {
92 m_root = index;
93 }
94
rootIndex() const95 QModelIndex ModelMenu::rootIndex() const
96 {
97 return m_root;
98 }
99
setHoverRole(int role)100 void ModelMenu::setHoverRole(int role)
101 {
102 m_hoverRole = role;
103 }
104
hoverRole() const105 int ModelMenu::hoverRole() const
106 {
107 return m_hoverRole;
108 }
109
setSeparatorRole(int role)110 void ModelMenu::setSeparatorRole(int role)
111 {
112 m_separatorRole = role;
113 }
114
separatorRole() const115 int ModelMenu::separatorRole() const
116 {
117 return m_separatorRole;
118 }
119
Q_DECLARE_METATYPE(QModelIndex)120 Q_DECLARE_METATYPE(QModelIndex)
121 void ModelMenu::aboutToShow()
122 {
123 if (QMenu *menu = qobject_cast<QMenu*>(sender())) {
124 QVariant v = menu->menuAction()->data();
125 if (v.canConvert<QModelIndex>()) {
126 QModelIndex idx = qvariant_cast<QModelIndex>(v);
127 createMenu(idx, -1, menu, menu);
128 disconnect(menu, SIGNAL(aboutToShow()), this, SLOT(aboutToShow()));
129 return;
130 }
131 }
132
133 clear();
134 if (prePopulated())
135 addSeparator();
136 int max = m_maxRows;
137 if (max != -1)
138 max += m_firstSeparator;
139 createMenu(m_root, max, this, this);
140 postPopulated();
141 }
142
createMenu(const QModelIndex & parent,int max,QMenu * parentMenu,QMenu * menu)143 void ModelMenu::createMenu(const QModelIndex &parent, int max, QMenu *parentMenu, QMenu *menu)
144 {
145 if (!menu) {
146 QString title = parent.data().toString();
147 menu = new QMenu(title, this);
148 QIcon icon = qvariant_cast<QIcon>(parent.data(Qt::DecorationRole));
149 menu->setIcon(icon);
150 parentMenu->addMenu(menu);
151 QVariant v;
152 v.setValue(parent);
153 menu->menuAction()->setData(v);
154 connect(menu, SIGNAL(aboutToShow()), this, SLOT(aboutToShow()));
155 return;
156 }
157
158 int end = m_model->rowCount(parent);
159 if (max != -1)
160 end = qMin(max, end);
161
162 connect(menu, SIGNAL(triggered(QAction*)), this, SLOT(triggered(QAction*)));
163 connect(menu, SIGNAL(hovered(QAction*)), this, SLOT(hovered(QAction*)));
164
165 for (int i = 0; i < end; ++i) {
166 QModelIndex idx = m_model->index(i, 0, parent);
167 if (m_model->hasChildren(idx)) {
168 createMenu(idx, -1, menu);
169 } else {
170 if (m_separatorRole != 0
171 && idx.data(m_separatorRole).toBool())
172 addSeparator();
173 else
174 menu->addAction(makeAction(idx));
175 }
176 if (menu == this && i == m_firstSeparator - 1)
177 addSeparator();
178 }
179 }
180
makeAction(const QModelIndex & index)181 QAction *ModelMenu::makeAction(const QModelIndex &index)
182 {
183 QIcon icon = qvariant_cast<QIcon>(index.data(Qt::DecorationRole));
184 QAction *action = makeAction(icon, index.data().toString(), this);
185 QVariant v;
186 v.setValue(index);
187 action->setData(v);
188 return action;
189 }
190
makeAction(const QIcon & icon,const QString & text,QObject * parent)191 QAction *ModelMenu::makeAction(const QIcon &icon, const QString &text, QObject *parent)
192 {
193 QFontMetrics fm(font());
194 if (-1 == m_maxWidth)
195 m_maxWidth = fm.width(QLatin1Char('m')) * 30;
196 QString smallText = fm.elidedText(text, Qt::ElideMiddle, m_maxWidth);
197 return new QAction(icon, smallText, parent);
198 }
199
triggered(QAction * action)200 void ModelMenu::triggered(QAction *action)
201 {
202 QVariant v = action->data();
203 if (v.canConvert<QModelIndex>()) {
204 QModelIndex idx = qvariant_cast<QModelIndex>(v);
205 emit activated(idx);
206 }
207 }
208
hovered(QAction * action)209 void ModelMenu::hovered(QAction *action)
210 {
211 QVariant v = action->data();
212 if (v.canConvert<QModelIndex>()) {
213 QModelIndex idx = qvariant_cast<QModelIndex>(v);
214 QString hoveredString = idx.data(m_hoverRole).toString();
215 if (!hoveredString.isEmpty())
216 emit hovered(hoveredString);
217 }
218 }
219
220