1 /**************************************************************************
2 * Otter Browser: Web browser controlled by the user, not vice-versa.
3 * Copyright (C) 2013 - 2018 Michal Dutkiewicz aka Emdek <michal@emdek.pl>
4 * Copyright (C) 2015 Piotr Wójcik <chocimier@tlen.pl>
5 * Copyright (C) 2016 - 2017 Jan Bajer aka bajasoft <jbajer@gmail.com>
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 **************************************************************************/
21 
22 #include "Window.h"
23 #include "MainWindow.h"
24 #include "WidgetFactory.h"
25 #include "../core/Application.h"
26 #include "../core/HistoryManager.h"
27 #include "../core/SettingsManager.h"
28 #include "../core/Utils.h"
29 #include "../modules/widgets/address/AddressWidget.h"
30 #include "../modules/widgets/search/SearchWidget.h"
31 #include "../modules/windows/web/WebContentsWidget.h"
32 
33 #include <QtCore/QTimer>
34 #include <QtGui/QPainter>
35 #include <QtWidgets/QBoxLayout>
36 #include <QtWidgets/QMdiSubWindow>
37 
38 namespace Otter
39 {
40 
41 quint64 Window::m_identifierCounter(0);
42 
WindowToolBarWidget(int identifier,Window * parent)43 WindowToolBarWidget::WindowToolBarWidget(int identifier, Window *parent) : ToolBarWidget(identifier, parent, parent)
44 {
45 }
46 
paintEvent(QPaintEvent * event)47 void WindowToolBarWidget::paintEvent(QPaintEvent *event)
48 {
49 	Q_UNUSED(event)
50 
51 	QPainter painter(this);
52 	QStyleOptionToolBar toolBarOption;
53 	toolBarOption.initFrom(this);
54 	toolBarOption.lineWidth = style()->pixelMetric(QStyle::PM_ToolBarFrameWidth, nullptr, this);
55 	toolBarOption.positionOfLine = QStyleOptionToolBar::End;
56 	toolBarOption.positionWithinLine = QStyleOptionToolBar::OnlyOne;
57 	toolBarOption.state |= QStyle::State_Horizontal;
58 	toolBarOption.toolBarArea = Qt::TopToolBarArea;
59 
60 	style()->drawControl(QStyle::CE_ToolBar, &toolBarOption, &painter, this);
61 }
62 
Window(const QVariantMap & parameters,ContentsWidget * widget,MainWindow * mainWindow)63 Window::Window(const QVariantMap &parameters, ContentsWidget *widget, MainWindow *mainWindow) : QWidget(mainWindow->centralWidget()), ActionExecutor(),
64 	m_mainWindow(mainWindow),
65 	m_addressBarWidget(nullptr),
66 	m_contentsWidget(nullptr),
67 	m_parameters(parameters),
68 	m_identifier(++m_identifierCounter),
69 	m_suspendTimer(0),
70 	m_isAboutToClose(false),
71 	m_isPinned(false)
72 {
73 	QBoxLayout *layout(new QBoxLayout(QBoxLayout::TopToBottom, this));
74 	layout->setContentsMargins(0, 0, 0, 0);
75 	layout->setSpacing(0);
76 
77 	setLayout(layout);
78 
79 	if (widget)
80 	{
81 		setContentsWidget(widget);
82 	}
83 
84 	connect(this, &Window::titleChanged, this, &Window::setWindowTitle);
85 	connect(this, &Window::iconChanged, this, &Window::handleIconChanged);
86 	connect(mainWindow, &MainWindow::toolBarStateChanged, this, &Window::handleToolBarStateChanged);
87 }
88 
timerEvent(QTimerEvent * event)89 void Window::timerEvent(QTimerEvent *event)
90 {
91 	if (event->timerId() == m_suspendTimer)
92 	{
93 		killTimer(m_suspendTimer);
94 
95 		m_suspendTimer = 0;
96 
97 		triggerAction(ActionsManager::SuspendTabAction);
98 	}
99 }
100 
hideEvent(QHideEvent * event)101 void Window::hideEvent(QHideEvent *event)
102 {
103 	QWidget::hideEvent(event);
104 
105 	const int suspendTime(SettingsManager::getOption(SettingsManager::Browser_InactiveTabTimeUntilSuspendOption).toInt());
106 
107 	if (m_suspendTimer == 0 && suspendTime >= 0)
108 	{
109 		m_suspendTimer = startTimer(suspendTime * 1000);
110 	}
111 }
112 
focusInEvent(QFocusEvent * event)113 void Window::focusInEvent(QFocusEvent *event)
114 {
115 	QWidget::focusInEvent(event);
116 
117 	if (m_suspendTimer != 0)
118 	{
119 		killTimer(m_suspendTimer);
120 
121 		m_suspendTimer = 0;
122 	}
123 
124 	updateFocus();
125 }
126 
triggerAction(int identifier,const QVariantMap & parameters,ActionsManager::TriggerType trigger)127 void Window::triggerAction(int identifier, const QVariantMap &parameters, ActionsManager::TriggerType trigger)
128 {
129 	switch (identifier)
130 	{
131 		case ActionsManager::CloneTabAction:
132 			if (canClone())
133 			{
134 				m_mainWindow->addWindow(clone(true, m_mainWindow));
135 			}
136 
137 			break;
138 		case ActionsManager::PinTabAction:
139 			setPinned(!isPinned());
140 
141 			break;
142 		case ActionsManager::DetachTabAction:
143 			if (m_mainWindow->getWindowCount() > 1 || parameters.value(QLatin1String("minimalInterface")).toBool())
144 			{
145 				m_mainWindow->moveWindow(this, nullptr, parameters);
146 			}
147 
148 			break;
149 		case ActionsManager::MaximizeTabAction:
150 		case ActionsManager::MinimizeTabAction:
151 		case ActionsManager::RestoreTabAction:
152 		case ActionsManager::AlwaysOnTopTabAction:
153 			{
154 				QVariantMap mutableParameters(parameters);
155 				mutableParameters[QLatin1String("tab")] = m_identifier;
156 
157 				m_mainWindow->triggerAction(identifier, mutableParameters, trigger);
158 			}
159 
160 			break;
161 		case ActionsManager::SuspendTabAction:
162 			if (!m_contentsWidget || m_contentsWidget->close())
163 			{
164 				m_session = getSession();
165 
166 				setContentsWidget(nullptr);
167 			}
168 
169 			break;
170 		case ActionsManager::CloseTabAction:
171 			if (!isPinned())
172 			{
173 				requestClose();
174 			}
175 
176 			break;
177 		case ActionsManager::FullScreenAction:
178 			if (m_contentsWidget)
179 			{
180 				m_contentsWidget->triggerAction(identifier, parameters, trigger);
181 			}
182 
183 			break;
184 		default:
185 			getContentsWidget()->triggerAction(identifier, parameters, trigger);
186 
187 			break;
188 	}
189 }
190 
clear()191 void Window::clear()
192 {
193 	if (!m_contentsWidget || m_contentsWidget->close())
194 	{
195 		setContentsWidget(new WebContentsWidget(m_parameters, {}, nullptr, this, this));
196 
197 		m_isAboutToClose = false;
198 
199 		emit urlChanged(getUrl(), true);
200 	}
201 }
202 
requestClose()203 void Window::requestClose()
204 {
205 	if (!m_contentsWidget || m_contentsWidget->close())
206 	{
207 		m_isAboutToClose = true;
208 
209 		emit aboutToClose();
210 
211 		QTimer::singleShot(50, this, [&]()
212 		{
213 			emit requestedCloseWindow(this);
214 		});
215 	}
216 }
217 
search(const QString & query,const QString & searchEngine)218 void Window::search(const QString &query, const QString &searchEngine)
219 {
220 	WebContentsWidget *widget(qobject_cast<WebContentsWidget*>(m_contentsWidget));
221 
222 	if (!widget)
223 	{
224 		if (m_contentsWidget && !m_contentsWidget->close())
225 		{
226 			return;
227 		}
228 
229 		QVariantMap parameters;
230 
231 		if (isPrivate())
232 		{
233 			parameters[QLatin1String("hints")] = SessionsManager::PrivateOpen;
234 		}
235 
236 		widget = new WebContentsWidget(parameters, {}, nullptr, this, this);
237 
238 		setContentsWidget(widget);
239 	}
240 
241 	widget->search(query, searchEngine);
242 
243 	emit urlChanged(getUrl(), true);
244 }
245 
markAsActive(bool updateLastActivity)246 void Window::markAsActive(bool updateLastActivity)
247 {
248 	if (m_suspendTimer != 0)
249 	{
250 		killTimer(m_suspendTimer);
251 
252 		m_suspendTimer = 0;
253 	}
254 
255 	if (!m_contentsWidget)
256 	{
257 		setUrl(m_session.getUrl(), false);
258 	}
259 
260 	if (updateLastActivity)
261 	{
262 		m_lastActivity = QDateTime::currentDateTime();
263 	}
264 
265 	emit activated();
266 }
267 
handleIconChanged(const QIcon & icon)268 void Window::handleIconChanged(const QIcon &icon)
269 {
270 	QMdiSubWindow *subWindow(qobject_cast<QMdiSubWindow*>(parentWidget()));
271 
272 	if (subWindow)
273 	{
274 		subWindow->setWindowIcon(icon);
275 	}
276 }
277 
handleSearchRequest(const QString & query,const QString & searchEngine,SessionsManager::OpenHints hints)278 void Window::handleSearchRequest(const QString &query, const QString &searchEngine, SessionsManager::OpenHints hints)
279 {
280 	if ((getType() == QLatin1String("web") && Utils::isUrlEmpty(getUrl())) || (hints == SessionsManager::DefaultOpen || hints == SessionsManager::CurrentTabOpen))
281 	{
282 		search(query, searchEngine);
283 	}
284 	else
285 	{
286 		emit requestedSearch(query, searchEngine, hints);
287 	}
288 }
289 
handleGeometryChangeRequest(const QRect & geometry)290 void Window::handleGeometryChangeRequest(const QRect &geometry)
291 {
292 	QMdiSubWindow *subWindow(qobject_cast<QMdiSubWindow*>(parentWidget()));
293 
294 	if (subWindow)
295 	{
296 		Application::triggerAction(ActionsManager::RestoreTabAction, {{QLatin1String("tab"), getIdentifier()}}, m_mainWindow);
297 
298 		subWindow->setWindowFlags(Qt::SubWindow);
299 		subWindow->showNormal();
300 		subWindow->resize(geometry.size() + (subWindow->geometry().size() - m_contentsWidget->size()));
301 		subWindow->move(geometry.topLeft());
302 	}
303 }
304 
handleToolBarStateChanged(int identifier,const ToolBarState & state)305 void Window::handleToolBarStateChanged(int identifier, const ToolBarState &state)
306 {
307 	if (m_addressBarWidget && identifier == ToolBarsManager::AddressBar)
308 	{
309 		m_addressBarWidget->setState(state);
310 	}
311 }
312 
updateFocus()313 void Window::updateFocus()
314 {
315 	QTimer::singleShot(100, this, [&]()
316 	{
317 		AddressWidget *addressWidget(m_mainWindow->findAddressField());
318 
319 		if (addressWidget && Utils::isUrlEmpty(getUrl()) && (!m_contentsWidget || m_contentsWidget->getLoadingState() != WebWidget::OngoingLoadingState))
320 		{
321 			addressWidget->setFocus();
322 		}
323 		else if (m_contentsWidget)
324 		{
325 			m_contentsWidget->setFocus();
326 		}
327 	});
328 }
329 
setSession(const SessionWindow & session,bool deferLoading)330 void Window::setSession(const SessionWindow &session, bool deferLoading)
331 {
332 	m_session = session;
333 
334 	setPinned(session.isPinned);
335 
336 	if (deferLoading)
337 	{
338 		setWindowTitle(session.getTitle());
339 	}
340 	else
341 	{
342 		setUrl(session.getUrl(), false);
343 	}
344 }
345 
setOption(int identifier,const QVariant & value)346 void Window::setOption(int identifier, const QVariant &value)
347 {
348 	if (m_contentsWidget)
349 	{
350 		m_contentsWidget->setOption(identifier, value);
351 	}
352 	else if (value != m_session.options.value(identifier))
353 	{
354 		if (value.isNull())
355 		{
356 			m_session.options.remove(identifier);
357 		}
358 		else
359 		{
360 			m_session.options[identifier] = value;
361 		}
362 
363 		SessionsManager::markSessionAsModified();
364 
365 		emit optionChanged(identifier, value);
366 	}
367 }
368 
setUrl(const QUrl & url,bool isTyped)369 void Window::setUrl(const QUrl &url, bool isTyped)
370 {
371 	ContentsWidget *newWidget(nullptr);
372 
373 	if (url.scheme() == QLatin1String("about") || url.scheme() == QLatin1String("view-feed"))
374 	{
375 		if (m_session.historyIndex < 0 && !Utils::isUrlEmpty(getUrl()) && SessionsManager::hasUrl(url, true))
376 		{
377 			emit urlChanged(url, true);
378 
379 			return;
380 		}
381 
382 		newWidget = WidgetFactory::createContentsWidget(((url.scheme() == QLatin1String("view-feed")) ? QLatin1String("feeds") : url.path()), {}, this, this);
383 
384 		if (newWidget)
385 		{
386 			newWidget->setUrl(url);
387 
388 			if (!newWidget->canClone())
389 			{
390 				SessionsManager::removeStoredUrl(newWidget->getUrl().toString());
391 			}
392 		}
393 	}
394 
395 	const bool isRestoring(!m_contentsWidget && m_session.historyIndex >= 0);
396 
397 	if (!newWidget && (!m_contentsWidget || m_contentsWidget->getType() != QLatin1String("web")))
398 	{
399 		newWidget = new WebContentsWidget(m_parameters, m_session.options, nullptr, this, this);
400 	}
401 
402 	if (newWidget)
403 	{
404 		if (m_contentsWidget && !m_contentsWidget->close())
405 		{
406 			return;
407 		}
408 
409 		setContentsWidget(newWidget);
410 	}
411 
412 	if (m_contentsWidget && url.isValid())
413 	{
414 		if (!isRestoring)
415 		{
416 			m_contentsWidget->setUrl(url, isTyped);
417 		}
418 
419 		if (!Utils::isUrlEmpty(getUrl()) || m_contentsWidget->getLoadingState() == WebWidget::OngoingLoadingState)
420 		{
421 			emit urlChanged(url, true);
422 		}
423 	}
424 }
425 
setZoom(int zoom)426 void Window::setZoom(int zoom)
427 {
428 	if (m_contentsWidget)
429 	{
430 		m_contentsWidget->setZoom(zoom);
431 	}
432 	else if (m_session.historyIndex >= 0 && m_session.historyIndex < m_session.history.count())
433 	{
434 		m_session.history[m_session.historyIndex].zoom = zoom;
435 	}
436 }
437 
setPinned(bool isPinned)438 void Window::setPinned(bool isPinned)
439 {
440 	if (isPinned != m_isPinned)
441 	{
442 		m_isPinned = isPinned;
443 
444 		emit arbitraryActionsStateChanged({ActionsManager::PinTabAction, ActionsManager::CloseTabAction});
445 		emit isPinnedChanged(isPinned);
446 	}
447 }
448 
setContentsWidget(ContentsWidget * widget)449 void Window::setContentsWidget(ContentsWidget *widget)
450 {
451 	if (m_contentsWidget)
452 	{
453 		layout()->removeWidget(m_contentsWidget);
454 
455 		m_contentsWidget->deleteLater();
456 	}
457 
458 	m_contentsWidget = widget;
459 
460 	if (!m_contentsWidget)
461 	{
462 		if (m_addressBarWidget)
463 		{
464 			layout()->removeWidget(m_addressBarWidget);
465 
466 			m_addressBarWidget->deleteLater();
467 			m_addressBarWidget = nullptr;
468 		}
469 
470 		emit actionsStateChanged();
471 
472 		return;
473 	}
474 
475 	m_contentsWidget->setParent(this);
476 
477 	if (!m_addressBarWidget)
478 	{
479 		m_addressBarWidget = new WindowToolBarWidget(ToolBarsManager::AddressBar, this);
480 		m_addressBarWidget->setState(m_mainWindow->getToolBarState(ToolBarsManager::AddressBar));
481 
482 		layout()->addWidget(m_addressBarWidget);
483 		layout()->setAlignment(m_addressBarWidget, Qt::AlignTop);
484 	}
485 
486 	layout()->addWidget(m_contentsWidget);
487 
488 	if (m_session.historyIndex >= 0 || !m_contentsWidget->getWebWidget() || m_contentsWidget->getWebWidget()->getRequestedUrl().isEmpty())
489 	{
490 		WindowHistoryInformation history;
491 
492 		if (m_session.historyIndex >= 0)
493 		{
494 			history.index = m_session.historyIndex;
495 			history.entries = m_session.history;
496 		}
497 
498 		m_contentsWidget->setHistory(history);
499 		m_contentsWidget->setZoom(m_session.getZoom());
500 	}
501 
502 	if (isActive())
503 	{
504 		if (m_session.historyIndex >= 0)
505 		{
506 			m_contentsWidget->setFocus();
507 		}
508 		else
509 		{
510 			const AddressWidget *addressWidget(m_mainWindow->findAddressField());
511 
512 			if (addressWidget && Utils::isUrlEmpty(m_contentsWidget->getUrl()))
513 			{
514 				QTimer::singleShot(100, addressWidget, static_cast<void(AddressWidget::*)()>(&AddressWidget::setFocus));
515 			}
516 		}
517 	}
518 
519 	updateFocus();
520 
521 	m_session = SessionWindow();
522 
523 	emit titleChanged(m_contentsWidget->getTitle());
524 	emit urlChanged(m_contentsWidget->getUrl(), false);
525 	emit iconChanged(m_contentsWidget->getIcon());
526 	emit actionsStateChanged();
527 	emit loadingStateChanged(m_contentsWidget->getLoadingState());
528 	emit canZoomChanged(m_contentsWidget->canZoom());
529 
530 	connect(m_contentsWidget, &ContentsWidget::aboutToNavigate, this, &Window::aboutToNavigate);
531 	connect(m_contentsWidget, &ContentsWidget::needsAttention, this, &Window::needsAttention);
532 	connect(m_contentsWidget, &ContentsWidget::requestedNewWindow, this, &Window::requestedNewWindow);
533 	connect(m_contentsWidget, &ContentsWidget::requestedSearch, this, &Window::requestedSearch);
534 	connect(m_contentsWidget, &ContentsWidget::requestedGeometryChange, this, &Window::handleGeometryChangeRequest);
535 	connect(m_contentsWidget, &ContentsWidget::statusMessageChanged, this, &Window::statusMessageChanged);
536 	connect(m_contentsWidget, &ContentsWidget::titleChanged, this, &Window::titleChanged);
537 	connect(m_contentsWidget, &ContentsWidget::urlChanged, this, [&](const QUrl &url)
538 	{
539 		emit urlChanged(url, false);
540 	});
541 	connect(m_contentsWidget, &ContentsWidget::iconChanged, this, &Window::iconChanged);
542 	connect(m_contentsWidget, &ContentsWidget::requestBlocked, this, &Window::requestBlocked);
543 	connect(m_contentsWidget, &ContentsWidget::arbitraryActionsStateChanged, this, &Window::arbitraryActionsStateChanged);
544 	connect(m_contentsWidget, &ContentsWidget::categorizedActionsStateChanged, this, &Window::categorizedActionsStateChanged);
545 	connect(m_contentsWidget, &ContentsWidget::contentStateChanged, this, &Window::contentStateChanged);
546 	connect(m_contentsWidget, &ContentsWidget::loadingStateChanged, this, &Window::loadingStateChanged);
547 	connect(m_contentsWidget, &ContentsWidget::pageInformationChanged, this, &Window::pageInformationChanged);
548 	connect(m_contentsWidget, &ContentsWidget::optionChanged, this, &Window::optionChanged);
549 	connect(m_contentsWidget, &ContentsWidget::zoomChanged, this, &Window::zoomChanged);
550 	connect(m_contentsWidget, &ContentsWidget::canZoomChanged, this, &Window::canZoomChanged);
551 	connect(m_contentsWidget, &ContentsWidget::webWidgetChanged, m_addressBarWidget, &WindowToolBarWidget::reload);
552 }
553 
clone(bool cloneHistory,MainWindow * mainWindow) const554 Window* Window::clone(bool cloneHistory, MainWindow *mainWindow) const
555 {
556 	if (!m_contentsWidget || !canClone())
557 	{
558 		return nullptr;
559 	}
560 
561 	QVariantMap parameters({{QLatin1String("size"), size()}});
562 
563 	if (isPrivate())
564 	{
565 		parameters[QLatin1String("hints")] = SessionsManager::PrivateOpen;
566 	}
567 
568 	return new Window(parameters, m_contentsWidget->clone(cloneHistory), mainWindow);
569 }
570 
getMainWindow() const571 MainWindow* Window::getMainWindow() const
572 {
573 	return m_mainWindow;
574 }
575 
getAddressBar() const576 WindowToolBarWidget* Window::getAddressBar() const
577 {
578 	return m_addressBarWidget;
579 }
580 
getContentsWidget()581 ContentsWidget* Window::getContentsWidget()
582 {
583 	if (!m_contentsWidget)
584 	{
585 		setUrl(m_session.getUrl(), false);
586 	}
587 
588 	return m_contentsWidget;
589 }
590 
getWebWidget()591 WebWidget* Window::getWebWidget()
592 {
593 	if (!m_contentsWidget)
594 	{
595 		setUrl(m_session.getUrl(), false);
596 	}
597 
598 	return m_contentsWidget->getWebWidget();
599 }
600 
getTitle() const601 QString Window::getTitle() const
602 {
603 	return ((m_contentsWidget && !m_isAboutToClose) ? m_contentsWidget->getTitle() : m_session.getTitle());
604 }
605 
getType() const606 QLatin1String Window::getType() const
607 {
608 	return ((m_contentsWidget && !m_isAboutToClose) ? m_contentsWidget->getType() : QLatin1String("unknown"));
609 }
610 
getOption(int identifier) const611 QVariant Window::getOption(int identifier) const
612 {
613 	if (m_contentsWidget)
614 	{
615 		return m_contentsWidget->getOption(identifier);
616 	}
617 
618 	return (m_session.options.contains(identifier) ? m_session.options[identifier] : SettingsManager::getOption(identifier, m_session.getUrl()));
619 }
620 
getUrl() const621 QUrl Window::getUrl() const
622 {
623 	return ((m_contentsWidget && !m_isAboutToClose) ? m_contentsWidget->getUrl() : m_session.getUrl());
624 }
625 
getIcon() const626 QIcon Window::getIcon() const
627 {
628 	return ((m_contentsWidget && !m_isAboutToClose) ? m_contentsWidget->getIcon() : HistoryManager::getIcon(m_session.getUrl()));
629 }
630 
createThumbnail() const631 QPixmap Window::createThumbnail() const
632 {
633 	return ((m_contentsWidget && !m_isAboutToClose) ? m_contentsWidget->createThumbnail() : QPixmap());
634 }
635 
getLastActivity() const636 QDateTime Window::getLastActivity() const
637 {
638 	return m_lastActivity;
639 }
640 
getActionState(int identifier,const QVariantMap & parameters) const641 ActionsManager::ActionDefinition::State Window::getActionState(int identifier, const QVariantMap &parameters) const
642 {
643 	ActionsManager::ActionDefinition::State state(ActionsManager::getActionDefinition(identifier).getDefaultState());
644 
645 	switch (identifier)
646 	{
647 		case ActionsManager::CloneTabAction:
648 			state.isEnabled = canClone();
649 
650 			break;
651 		case ActionsManager::DetachTabAction:
652 			state.isEnabled = (m_mainWindow->getWindowCount() > 1 || parameters.value(QLatin1String("minimalInterface")).toBool());
653 
654 			break;
655 		case ActionsManager::PinTabAction:
656 			state.text = (m_isPinned ? QCoreApplication::translate("actions", "Unpin Tab") : QCoreApplication::translate("actions", "Pin Tab"));
657 
658 			break;
659 		case ActionsManager::CloseTabAction:
660 			state.isEnabled = !m_isPinned;
661 
662 			break;
663 		case ActionsManager::GoToParentDirectoryAction:
664 			state.isEnabled = !Utils::isUrlEmpty(getUrl());
665 
666 			break;
667 		case ActionsManager::MaximizeTabAction:
668 			state.isEnabled = (getWindowState().state != Qt::WindowMaximized);
669 
670 			break;
671 		case ActionsManager::MinimizeTabAction:
672 			state.isEnabled = (getWindowState().state != Qt::WindowMinimized);
673 
674 			break;
675 		case ActionsManager::RestoreTabAction:
676 			state.isEnabled = (getWindowState().state != Qt::WindowNoState);
677 
678 			break;
679 		case ActionsManager::AlwaysOnTopTabAction:
680 			{
681 				const QMdiSubWindow *subWindow(qobject_cast<QMdiSubWindow*>(parentWidget()));
682 
683 				if (subWindow)
684 				{
685 					state.isEnabled = subWindow->windowFlags().testFlag(Qt::WindowStaysOnTopHint);
686 				}
687 			}
688 
689 			break;
690 		default:
691 			if (m_contentsWidget)
692 			{
693 				state = m_contentsWidget->getActionState(identifier, parameters);
694 			}
695 
696 			break;
697 	}
698 
699 	return state;
700 }
701 
getHistory() const702 WindowHistoryInformation Window::getHistory() const
703 {
704 	if (m_contentsWidget)
705 	{
706 		return m_contentsWidget->getHistory();
707 	}
708 
709 	WindowHistoryInformation history;
710 	history.entries = m_session.history;
711 	history.index = m_session.historyIndex;
712 
713 	return history;
714 }
715 
getSession() const716 SessionWindow Window::getSession() const
717 {
718 	const QMdiSubWindow *subWindow(qobject_cast<QMdiSubWindow*>(parentWidget()));
719 	SessionWindow session;
720 
721 	if (m_contentsWidget)
722 	{
723 		const WindowHistoryInformation history(m_contentsWidget->getHistory());
724 
725 		if (m_contentsWidget->getType() == QLatin1String("web"))
726 		{
727 			const WebContentsWidget *webWidget(qobject_cast<WebContentsWidget*>(m_contentsWidget));
728 
729 			if (webWidget)
730 			{
731 				session.options = webWidget->getOptions();
732 			}
733 		}
734 
735 		session.history = history.entries;
736 		session.parentGroup = 0;
737 		session.historyIndex = history.index;
738 		session.isPinned = isPinned();
739 	}
740 	else
741 	{
742 		session = m_session;
743 	}
744 
745 	session.state = getWindowState();
746 	session.isAlwaysOnTop = (subWindow && subWindow->windowFlags().testFlag(Qt::WindowStaysOnTopHint));
747 
748 	return session;
749 }
750 
getWindowState() const751 WindowState Window::getWindowState() const
752 {
753 	const QMdiSubWindow *subWindow(qobject_cast<QMdiSubWindow*>(parentWidget()));
754 	WindowState windowState;
755 	windowState.state = Qt::WindowMaximized;
756 
757 	if (subWindow && !subWindow->isMaximized())
758 	{
759 		if (subWindow->isMinimized())
760 		{
761 			windowState.state = Qt::WindowMinimized;
762 		}
763 		else
764 		{
765 			windowState.geometry = subWindow->geometry();
766 			windowState.state = Qt::WindowNoState;
767 		}
768 	}
769 
770 	return windowState;
771 }
772 
sizeHint() const773 QSize Window::sizeHint() const
774 {
775 	return QSize(800, 600);
776 }
777 
getLoadingState() const778 WebWidget::LoadingState Window::getLoadingState() const
779 {
780 	return ((m_contentsWidget && !m_isAboutToClose) ? m_contentsWidget->getLoadingState() : WebWidget::DeferredLoadingState);
781 }
782 
getContentState() const783 WebWidget::ContentStates Window::getContentState() const
784 {
785 	return ((m_contentsWidget && !m_isAboutToClose) ? m_contentsWidget->getContentState() : WebWidget::UnknownContentState);
786 }
787 
getIdentifier() const788 quint64 Window::getIdentifier() const
789 {
790 	return m_identifier;
791 }
792 
getZoom() const793 int Window::getZoom() const
794 {
795 	return ((m_contentsWidget && !m_isAboutToClose) ? m_contentsWidget->getZoom() : m_session.getZoom());
796 }
797 
canClone() const798 bool Window::canClone() const
799 {
800 	return ((m_contentsWidget && !m_isAboutToClose) ? m_contentsWidget->canClone() : false);
801 }
802 
canZoom() const803 bool Window::canZoom() const
804 {
805 	return ((m_contentsWidget && !m_isAboutToClose) ? m_contentsWidget->canZoom() : false);
806 }
807 
isAboutToClose() const808 bool Window::isAboutToClose() const
809 {
810 	return m_isAboutToClose;
811 }
812 
isActive() const813 bool Window::isActive() const
814 {
815 	return (isActiveWindow() && isAncestorOf(QApplication::focusWidget()));
816 }
817 
isPinned() const818 bool Window::isPinned() const
819 {
820 	return m_isPinned;
821 }
822 
isPrivate() const823 bool Window::isPrivate() const
824 {
825 	return ((m_contentsWidget && !m_isAboutToClose) ? m_contentsWidget->isPrivate() : SessionsManager::calculateOpenHints(m_parameters).testFlag(SessionsManager::PrivateOpen));
826 }
827 
event(QEvent * event)828 bool Window::event(QEvent *event)
829 {
830 	if (event->type() == QEvent::ParentChange)
831 	{
832 		const QMdiSubWindow *subWindow(qobject_cast<QMdiSubWindow*>(parentWidget()));
833 
834 		if (subWindow)
835 		{
836 			connect(subWindow, &QMdiSubWindow::windowStateChanged, [&]()
837 			{
838 				emit arbitraryActionsStateChanged({ActionsManager::MaximizeTabAction, ActionsManager::MinimizeTabAction, ActionsManager::RestoreTabAction});
839 			});
840 		}
841 	}
842 
843 	return QWidget::event(event);
844 }
845 
846 }
847