1 /**************************************************************************
2 * Otter Browser: Web browser controlled by the user, not vice-versa.
3 * Copyright (C) 2015 - 2018 Michal Dutkiewicz aka Emdek <michal@emdek.pl>
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 **************************************************************************/
19 
20 #include "ToolButtonWidget.h"
21 #include "Action.h"
22 #include "MainWindow.h"
23 #include "Menu.h"
24 #include "ToolBarWidget.h"
25 #include "../core/Application.h"
26 #include "../core/ThemesManager.h"
27 
28 #include <QtCore/QEvent>
29 #include <QtGui/QActionEvent>
30 #include <QtWidgets/QStyleOptionToolButton>
31 #include <QtWidgets/QStylePainter>
32 
33 namespace Otter
34 {
35 
ToolButtonWidget(const ToolBarsManager::ToolBarDefinition::Entry & definition,QWidget * parent)36 ToolButtonWidget::ToolButtonWidget(const ToolBarsManager::ToolBarDefinition::Entry &definition, QWidget *parent) : QToolButton(parent),
37 	m_parameters(definition.parameters),
38 	m_isCustomized(false)
39 {
40 	setAutoRaise(true);
41 	setContextMenuPolicy(Qt::NoContextMenu);
42 	setOptions(definition.options);
43 
44 	Menu *menu(nullptr);
45 
46 	if (!definition.entries.isEmpty())
47 	{
48 		menu = new Menu(Menu::UnknownMenu, this);
49 
50 		addMenu(menu, definition.entries);
51 		setMenu(menu);
52 	}
53 	else if (definition.action == QLatin1String("OptionMenu") && definition.options.contains(QLatin1String("option")))
54 	{
55 		menu = new Menu(Menu::UnknownMenu, this);
56 		menu->load(SettingsManager::getOptionIdentifier(definition.options[QLatin1String("option")].toString()));
57 
58 		setDefaultAction(menu->menuAction());
59 	}
60 	else if (definition.action.endsWith(QLatin1String("Menu")))
61 	{
62 		menu = new Menu(Menu::getMenuRoleIdentifier(definition.action), this);
63 
64 		setDefaultAction(menu->menuAction());
65 	}
66 
67 	if (menu)
68 	{
69 		menu->setActionParameters(definition.parameters);
70 		menu->setMenuOptions(definition.options);
71 
72 		setPopupMode(QToolButton::InstantPopup);
73 		setText(getText());
74 		setToolTip(getText());
75 		setIcon(getIcon());
76 	}
77 
78 	const ToolBarWidget *toolBar(qobject_cast<ToolBarWidget*>(parent));
79 
80 	if (toolBar)
81 	{
82 		setButtonStyle(toolBar->getButtonStyle());
83 		setIconSize(toolBar->getIconSize());
84 		setMaximumButtonSize(toolBar->getMaximumButtonSize());
85 
86 		connect(toolBar, &ToolBarWidget::buttonStyleChanged, this, &ToolButtonWidget::setButtonStyle);
87 		connect(toolBar, &ToolBarWidget::iconSizeChanged, this, &ToolButtonWidget::setIconSize);
88 		connect(toolBar, &ToolBarWidget::maximumButtonSizeChanged, this, &ToolButtonWidget::setMaximumButtonSize);
89 	}
90 }
91 
actionEvent(QActionEvent * event)92 void ToolButtonWidget::actionEvent(QActionEvent *event)
93 {
94 	QToolButton::actionEvent(event);
95 
96 	if (event->type() == QEvent::ActionChanged || event->type() == QEvent::ActionAdded)
97 	{
98 		setText(getText());
99 		setIcon(getIcon());
100 	}
101 }
102 
paintEvent(QPaintEvent * event)103 void ToolButtonWidget::paintEvent(QPaintEvent *event)
104 {
105 	Q_UNUSED(event)
106 
107 	QStylePainter painter(this);
108 	QStyleOptionToolButton option;
109 
110 	initStyleOption(&option);
111 
112 	option.text = option.fontMetrics.elidedText(option.text, (isLeftToRight() ? Qt::ElideRight : Qt::ElideLeft), (option.rect.width() - (option.fontMetrics.width(QLatin1Char(' ')) * 2) - ((toolButtonStyle() == Qt::ToolButtonTextBesideIcon) ? iconSize().width() : 0)));
113 
114 	painter.drawComplexControl(QStyle::CC_ToolButton, option);
115 }
116 
addMenu(Menu * menu,const QVector<ToolBarsManager::ToolBarDefinition::Entry> & entries)117 void ToolButtonWidget::addMenu(Menu *menu, const QVector<ToolBarsManager::ToolBarDefinition::Entry> &entries)
118 {
119 	const ToolBarWidget *toolBar(qobject_cast<ToolBarWidget*>(parentWidget()));
120 	ActionExecutor::Object executor(Application::getInstance(), Application::getInstance());
121 
122 	if (toolBar && toolBar->getMainWindow())
123 	{
124 		executor = ActionExecutor::Object(toolBar->getMainWindow(), toolBar->getMainWindow());
125 	}
126 
127 	for (int i = 0; i < entries.count(); ++i)
128 	{
129 		const ToolBarsManager::ToolBarDefinition::Entry entry(entries.at(i));
130 
131 		if (entry.entries.isEmpty())
132 		{
133 			if (entry.action.isEmpty() || entry.action == QLatin1String("separator"))
134 			{
135 				menu->addSeparator();
136 			}
137 			else
138 			{
139 				menu->addAction(new Action(ActionsManager::getActionIdentifier(entry.action), entry.parameters, entry.options, executor, menu));
140 			}
141 		}
142 		else
143 		{
144 			Menu *subMenu(new Menu());
145 			QAction *subMenuAction(new QAction(menu));
146 			subMenuAction->setText(entry.options.value(QLatin1String("text"), tr("Menu")).toString());
147 			subMenuAction->setMenu(subMenu);
148 
149 			menu->addAction(subMenuAction);
150 
151 			addMenu(subMenu, entry.entries);
152 		}
153 	}
154 }
155 
setOptions(const QVariantMap & options)156 void ToolButtonWidget::setOptions(const QVariantMap &options)
157 {
158 	m_options = options;
159 	m_isCustomized = (options.contains(QLatin1String("icon")) || options.contains(QLatin1String("text")));
160 
161 	if (m_isCustomized)
162 	{
163 		if (options.contains(QLatin1String("text")))
164 		{
165 			setText(getText());
166 		}
167 
168 		if (options.contains(QLatin1String("icon")))
169 		{
170 			setIcon(getIcon());
171 		}
172 	}
173 
174 	setButtonStyle(toolButtonStyle());
175 	update();
176 }
177 
setButtonStyle(Qt::ToolButtonStyle buttonStyle)178 void ToolButtonWidget::setButtonStyle(Qt::ToolButtonStyle buttonStyle)
179 {
180 	if (m_options.contains(QLatin1String("buttonStyle")))
181 	{
182 		const QString buttonStyleString(m_options[QLatin1String("buttonStyle")].toString());
183 
184 		if (buttonStyleString == QLatin1String("auto"))
185 		{
186 			buttonStyle = Qt::ToolButtonFollowStyle;
187 		}
188 		else if (buttonStyleString == QLatin1String("textOnly"))
189 		{
190 			buttonStyle = Qt::ToolButtonTextOnly;
191 		}
192 		else if (buttonStyleString == QLatin1String("textBesideIcon"))
193 		{
194 			buttonStyle = Qt::ToolButtonTextBesideIcon;
195 		}
196 		else if (buttonStyleString == QLatin1String("textUnderIcon"))
197 		{
198 			buttonStyle = Qt::ToolButtonTextUnderIcon;
199 		}
200 		else
201 		{
202 			buttonStyle = Qt::ToolButtonIconOnly;
203 		}
204 	}
205 
206 	setToolButtonStyle(buttonStyle);
207 }
208 
setIconSize(int size)209 void ToolButtonWidget::setIconSize(int size)
210 {
211 	QToolButton::setIconSize(QSize(size, size));
212 }
213 
setMaximumButtonSize(int size)214 void ToolButtonWidget::setMaximumButtonSize(int size)
215 {
216 	if (size > 0)
217 	{
218 		setMaximumSize(size, size);
219 	}
220 	else
221 	{
222 		setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
223 	}
224 }
225 
getText() const226 QString ToolButtonWidget::getText() const
227 {
228 	if (m_isCustomized && m_options.contains(QLatin1String("text")))
229 	{
230 		return m_options[QLatin1String("text")].toString();
231 	}
232 
233 	if (defaultAction())
234 	{
235 		return defaultAction()->text();
236 	}
237 
238 	return text();
239 }
240 
getIcon() const241 QIcon ToolButtonWidget::getIcon() const
242 {
243 	if (m_isCustomized && m_options.contains(QLatin1String("icon")))
244 	{
245 		const QVariant iconData(m_options[QLatin1String("icon")]);
246 
247 		if (iconData.type() == QVariant::Icon)
248 		{
249 			return iconData.value<QIcon>();
250 		}
251 
252 		return ThemesManager::createIcon(iconData.toString());
253 	}
254 
255 	return (defaultAction() ? defaultAction()->icon() : icon());
256 }
257 
getOptions() const258 QVariantMap ToolButtonWidget::getOptions() const
259 {
260 	return m_options;
261 }
262 
getParameters() const263 QVariantMap ToolButtonWidget::getParameters() const
264 {
265 	return m_parameters;
266 }
267 
isCustomized() const268 bool ToolButtonWidget::isCustomized() const
269 {
270 	return m_isCustomized;
271 }
272 
event(QEvent * event)273 bool ToolButtonWidget::event(QEvent *event)
274 {
275 	switch (event->type())
276 	{
277 		case QEvent::MouseButtonPress:
278 		case QEvent::MouseButtonRelease:
279 			if (!isEnabled())
280 			{
281 				return false;
282 			}
283 
284 			break;
285 		case QEvent::ContextMenu:
286 			if (contextMenuPolicy() == Qt::NoContextMenu)
287 			{
288 				return false;
289 			}
290 
291 			break;
292 		default:
293 			break;
294 	}
295 
296 	return QToolButton::event(event);
297 }
298 
299 }
300