1 /**************************************************************************
2 * Otter Browser: Web browser controlled by the user, not vice-versa.
3 * Copyright (C) 2015 - 2019 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 "MenuBarWidget.h"
21 #include "MainWindow.h"
22 #include "Menu.h"
23 #include "ToolBarWidget.h"
24 #include "../core/SessionsManager.h"
25 
26 #include <QtCore/QFile>
27 #include <QtCore/QJsonArray>
28 #include <QtCore/QJsonDocument>
29 #include <QtCore/QJsonObject>
30 #include <QtCore/QTimer>
31 #include <QtGui/QContextMenuEvent>
32 #include <QtWidgets/QStyle>
33 #include <QtWidgets/QStyleOptionMenuItem>
34 
35 namespace Otter
36 {
37 
MenuBarWidget(MainWindow * parent)38 MenuBarWidget::MenuBarWidget(MainWindow *parent) : QMenuBar(parent),
39 	m_mainWindow(parent),
40 	m_leftToolBar(nullptr),
41 	m_rightToolBar(nullptr)
42 {
43 	QFile file(SessionsManager::getReadableDataPath(QLatin1String("menu/menuBar.json")));
44 	file.open(QIODevice::ReadOnly);
45 
46 	const QJsonArray definition(QJsonDocument::fromJson(file.readAll()).array());
47 
48 	file.close();
49 
50 	for (int i = 0; i < definition.count(); ++i)
51 	{
52 		const QJsonObject object(definition.at(i).toObject());
53 		Menu *menu(new Menu(Menu::getMenuRoleIdentifier(object.value(QLatin1String("identifier")).toString()), this));
54 		menu->load(object);
55 
56 		addMenu(menu);
57 	}
58 
59 	if (!isNativeMenuBar())
60 	{
61 		reload();
62 
63 		connect(ToolBarsManager::getInstance(), &ToolBarsManager::toolBarModified, this, [&](int identifier)
64 		{
65 			if (identifier == ToolBarsManager::MenuBar)
66 			{
67 				reload();
68 			}
69 		});
70 	}
71 }
72 
changeEvent(QEvent * event)73 void MenuBarWidget::changeEvent(QEvent *event)
74 {
75 	QMenuBar::changeEvent(event);
76 
77 	if (event->type() == QEvent::LanguageChange)
78 	{
79 		QTimer::singleShot(100, this, &MenuBarWidget::updateGeometries);
80 	}
81 }
82 
resizeEvent(QResizeEvent * event)83 void MenuBarWidget::resizeEvent(QResizeEvent *event)
84 {
85 	QMenuBar::resizeEvent(event);
86 
87 	updateGeometries();
88 }
89 
contextMenuEvent(QContextMenuEvent * event)90 void MenuBarWidget::contextMenuEvent(QContextMenuEvent *event)
91 {
92 	QMenu *menu(ToolBarWidget::createCustomizationMenu(ToolBarsManager::MenuBar));
93 	menu->exec(event->globalPos());
94 	menu->deleteLater();
95 }
96 
reload()97 void MenuBarWidget::reload()
98 {
99 	const ToolBarsManager::ToolBarDefinition definition(ToolBarsManager::getToolBarDefinition(ToolBarsManager::MenuBar));
100 	QStringList actions;
101 	actions.reserve(definition.entries.count());
102 
103 	for (int i = 0; i < definition.entries.count(); ++i)
104 	{
105 		actions.append(definition.entries.at(i).action);
106 	}
107 
108 	if (actions.count() == 1 && actions.at(0) == QLatin1String("MenuBarWidget"))
109 	{
110 		if (m_leftToolBar)
111 		{
112 			m_leftToolBar->deleteLater();
113 			m_leftToolBar = nullptr;
114 
115 			setCornerWidget(nullptr, Qt::TopLeftCorner);
116 		}
117 
118 		if (m_rightToolBar)
119 		{
120 			m_rightToolBar->deleteLater();
121 			m_rightToolBar = nullptr;
122 
123 			setCornerWidget(nullptr, Qt::TopRightCorner);
124 		}
125 
126 		return;
127 	}
128 
129 	const int position(actions.indexOf(QLatin1String("MenuBarWidget")));
130 	const bool needsLeftToolbar(position != 0);
131 	const bool needsRightToolbar(position != (definition.entries.count() - 1));
132 
133 	if (needsLeftToolbar && !m_leftToolBar)
134 	{
135 		m_leftToolBar = new ToolBarWidget(ToolBarsManager::MenuBar, m_mainWindow->getActiveWindow(), this);
136 
137 		setCornerWidget(m_leftToolBar, Qt::TopLeftCorner);
138 	}
139 	else if (!needsLeftToolbar && m_leftToolBar)
140 	{
141 		m_leftToolBar->deleteLater();
142 		m_leftToolBar = nullptr;
143 
144 		setCornerWidget(nullptr, Qt::TopLeftCorner);
145 	}
146 
147 	if (needsRightToolbar && !m_rightToolBar)
148 	{
149 		m_rightToolBar = new ToolBarWidget(ToolBarsManager::MenuBar, m_mainWindow->getActiveWindow(), this);
150 
151 		setCornerWidget(m_rightToolBar, Qt::TopRightCorner);
152 	}
153 	else if (!needsRightToolbar && m_rightToolBar)
154 	{
155 		m_rightToolBar->deleteLater();
156 		m_rightToolBar = nullptr;
157 
158 		setCornerWidget(nullptr, Qt::TopRightCorner);
159 	}
160 
161 	ToolBarsManager::ToolBarDefinition leftDefinition(definition);
162 	leftDefinition.entries.clear();
163 
164 	ToolBarsManager::ToolBarDefinition rightDefinition(definition);
165 	rightDefinition.entries.clear();
166 
167 	for (int i = 0; i < definition.entries.count(); ++i)
168 	{
169 		if (i != position)
170 		{
171 			if (i < position)
172 			{
173 				leftDefinition.entries.append(definition.entries.at(i));
174 			}
175 			else
176 			{
177 				rightDefinition.entries.append(definition.entries.at(i));
178 			}
179 		}
180 	}
181 
182 	const int menuBarHeight(actionGeometry(this->actions().at(0)).height());
183 
184 	if (m_leftToolBar || m_rightToolBar)
185 	{
186 		const int toolBarHeight((m_leftToolBar ? m_leftToolBar->getIconSize() : m_rightToolBar->getIconSize()) + 12);
187 
188 		if (m_leftToolBar)
189 		{
190 			m_leftToolBar->setDefinition(leftDefinition);
191 		}
192 
193 		if (m_rightToolBar)
194 		{
195 			m_rightToolBar->setDefinition(rightDefinition);
196 		}
197 
198 		setFixedHeight((toolBarHeight > menuBarHeight) ? toolBarHeight : menuBarHeight);
199 	}
200 	else
201 	{
202 		setFixedHeight(menuBarHeight);
203 	}
204 
205 	QTimer::singleShot(100, this, &MenuBarWidget::updateGeometries);
206 }
207 
updateGeometries()208 void MenuBarWidget::updateGeometries()
209 {
210 	if (!m_leftToolBar && !m_rightToolBar)
211 	{
212 		return;
213 	}
214 
215 	int size(0);
216 
217 	if (actions().count() > 0)
218 	{
219 		size = ((style()->pixelMetric(QStyle::PM_MenuBarHMargin, nullptr, this) * 2) + (style()->pixelMetric(QStyle::PM_MenuBarItemSpacing, nullptr, this) * actions().count()));
220 
221 		for (int i = 0; i < actions().count(); ++i)
222 		{
223 			QStyleOptionMenuItem option;
224 
225 			initStyleOption(&option, actions().at(i));
226 
227 			size += style()->sizeFromContents(QStyle::CT_MenuBarItem, &option, fontMetrics().size(Qt::TextShowMnemonic, option.text), this).width();
228 		}
229 	}
230 
231 	if (m_rightToolBar && width() > (size + (m_leftToolBar ? m_leftToolBar->sizeHint().width() : 0) + (m_rightToolBar ? m_rightToolBar->sizeHint().width() : 0)))
232 	{
233 		const int offset(size - (m_leftToolBar ? m_leftToolBar->sizeHint().width() : 0));
234 		ToolBarWidget *toolBar(qobject_cast<ToolBarWidget*>(m_rightToolBar));
235 		toolBar->move(QPoint(offset, 0));
236 		toolBar->resize((width() - offset), toolBar->height());
237 	}
238 }
239 
240 }
241