view demos/browser/browsermainwindow.d @ 74:37caa90ce503

more porting
author mandel
date Fri, 22 May 2009 23:43:58 +0000
parents 7bfd46c330dc
children 0654fc9bac95
line wrap: on
line source
/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Qt Software Information (qt-info@nokia.com)
**
** This file is part of the demonstration applications of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial Usage
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
** $QT_END_LICENSE$
**
****************************************************************************/
module browsermainwindow;


import qt.core.QUrl;
import qt.core.QSettings;
import qt.gui.QMainWindow;
import qt.gui.QIcon;
import qt.gui.QDesktopWidget;
import qt.gui.QFileDialog;
import qt.gui.QPlainTextEdit;
import qt.gui.QPrintDialog;
import qt.gui.QPrintPreviewDialog;
import qt.gui.QPrinter;
import qt.gui.QMenuBar;
import qt.gui.QMessageBox;
import qt.gui.QStatusBar;
import qt.gui.QToolBar;
import qt.gui.QInputDialog;

import qt.core.QDebug;

import qt.webkit.QWebFrame;
import qt.webkit.QWebHistory;

import autosaver;
import bookmarks;
import browserapplication;
import chasewidget;
import downloadmanager;
import history;
import settings;
import tabwidget;
import toolbarsearch;
import webview;
import ui_passworddialog;


/*!
The MainWindow of the Browser Application.

Handles the tab widget and all the actions
*/
class BrowserMainWindow : public QMainWindow
{
	
static const qint32 BrowserMainWindowMagic = 0xba;

public:

	this(QWidget parent = null, Qt.WindowFlags flags = 0)
	{
		super(parent, flags);
		m_tabWidget = new TabWidget(this);
		m_autoSaver = new AutoSaver(this);
		m_historyBack = 0;
		m_historyForward = 0;
		m_stop = 0;
		m_reload = 0;

		setAttribute(Qt.WA_DeleteOnClose, true);
		statusBar().setSizeGripEnabled(true);
		setupMenu();
		setupToolBar();

		QWidget centralWidget = new QWidget(this);
		BookmarksModel boomarksModel = BrowserApplication.bookmarksManager().bookmarksModel();
		m_bookmarksToolbar = new BookmarksToolBar(boomarksModel, this);
		m_bookmarksToolba.openUrl.connect(&m_tabWidget.loadUrlInCurrentTab);
		m_bookmarksToolbar.toggleViewAction.toggled.connect(&thisupdateBookmarksToolbarActionText);

		QVBoxLayout layout = new QVBoxLayout;
		layout.setSpacing(0);
		layout.setMargin(0);
		version(Q_WS_MAC)
		{
			layout.addWidget(m_bookmarksToolbar);
			layout.addWidget(new QWidget); // <- OS X tab widget style bug
		} else {
			addToolBarBreak();
			addToolBar(m_bookmarksToolbar);
		}
		layout.addWidget(m_tabWidget);
		centralWidget.setLayout(layout);
		setCentralWidget(centralWidget);

		m_tabWidget.loadPage.connect(&thisloadPage);
		m_tabWidget.setCurrentTitle.connect(&this.slotUpdateWindowTitle);
		m_tabWidget.showStatusBarMessage.connect(&statusBar().showMessage);
		m_tabWidget.linkHovered.connect(&statusBar().showMessage);
		m_tabWidget.loadProgress.connect(&this.slotLoadProgress);
		m_tabWidget.tabsChanged.connect(&m_autoSaver.changeOccurred);
		m_tabWidget.geometryChangeRequested.connect(&this.geometryChangeRequested);
		m_tabWidget.printRequested.connect(&this.printRequested);
		m_tabWidget.menuBarVisibilityChangeRequested.connect(&menuBar().setVisible);
		m_tabWidget.statusBarVisibilityChangeRequested.connect(&statusBar().setVisible);
		m_tabWidget.toolBarVisibilityChangeRequested.connect(&m_navigationBar.setVisible);
		m_tabWidget.toolBarVisibilityChangeRequested.connect(&m_bookmarksToolbar.setVisible);
		version(Q_WS_MAC) {
			m_tabWidget.lastTabClosed().connect(&thisclose);
		} else {
			m_tabWidget.lastTabClosed().connect(&m_tabWidget.newTab);
		}

		slotUpdateWindowTitle();
		loadDefaultState();
		m_tabWidget.newTab();

		int size = m_tabWidget.lineEditStack().sizeHint().height();
		m_navigationBar.setIconSize(QSize(size, size));
	}

	~this()
	{
		m_autoSaver.changeOccurred();
		m_autoSaver.saveIfNeccessary();
	}


	QSize sizeHint()
	{
		QRect desktopRect = QApplication.desktop().screenGeometry();
		QSize size = desktopRect.size() * qreal(0.9);
		return size;
	}

public:

	static QUrl guessUrlFromString(QString string)
	{
		QString urlStr = string.trimmed();
		auto test = new QRegExp(QLatin1String("^[a-zA-Z]+\\:.*"));

		// Check if it looks like a qualified URL. Try parsing it and see.
		bool hasSchema = test.exactMatch(urlStr);
		if (hasSchema) {
			QUrl url = QUrl.fromEncoded(urlStr.toUtf8(), QUrl.TolerantMode);
			if (url.isValid())
				return url;
		}

		// Might be a file.
		if (QFile.exists(urlStr)) {
			QFileInfo info(urlStr);
			return QUrl.fromLocalFile(info.absoluteFilePath());
		}

		// Might be a shorturl - try to detect the schema.
		if (!hasSchema) {
			int dotIndex = urlStr.indexOf(QLatin1Char('.'));
			if (dotIndex != -1) {
				QString prefix = urlStr.left(dotIndex).toLower();
				QByteArray schema = (prefix == QLatin1String("ftp")) ? prefix.toLatin1() : "http";
				QUrl url =
				QUrl.fromEncoded(schema + "://" + urlStr.toUtf8(), QUrl.TolerantMode);
				if (url.isValid())
					return url;
			}
		}

		// Fall back to QUrl's own tolerant parser.
		QUrl url = QUrl.fromEncoded(string.toUtf8(), QUrl.TolerantMode);

		// finally for cases where the user just types in a hostname add http
		if (url.scheme().isEmpty())
			url = QUrl.fromEncoded("http://" + string.toUtf8(), QUrl.TolerantMode);
		return url;
	}

	TabWidget tabWidget()
	{
		return m_tabWidget;
	}

	WebView currentTab()
	{
		return m_tabWidget.currentWebView();
	}

	QByteArray saveState(bool withTabs)
	{
		int version_ = 2;
		QByteArray data;
		auto stream = new QDataStream(&data, QIODevice.WriteOnly);

		stream << qint32(BrowserMainWindowMagic);
		stream << qint32(version_);

		stream << size();
		stream << !m_navigationBar.isHidden();
		stream << !m_bookmarksToolbar.isHidden();
		stream << !statusBar().isHidden();
		if (withTabs)
			stream << tabWidget().saveState();
		else
			stream << QByteArray();
		return data;
	}


	bool restoreState(QByteArray state)
	{
		int version_ = 2;
		QByteArray sd = state;
		auto stream = new QDataStream(&sd, QIODevice.ReadOnly);
		if (stream.atEnd())
			return false;

		qint32 marker;
		qint32 v;
		stream >> marker;
		stream >> v;
		if (marker != BrowserMainWindowMagic || v != version_)
			return false;

		QSize size;
		bool showToolbar;
		bool showBookmarksBar;
		bool showStatusbar;
		QByteArray tabState;

		stream >> size;
		stream >> showToolbar;
		stream >> showBookmarksBar;
		stream >> showStatusbar;
		stream >> tabState;

		resize(size);

		m_navigationBar.setVisible(showToolbar);
		updateToolbarActionText(showToolbar);

		m_bookmarksToolbar.setVisible(showBookmarksBar);
		updateBookmarksToolbarActionText(showBookmarksBar);

		statusBar().setVisible(showStatusbar);
		updateStatusbarActionText(showStatusbar);

		if (!tabWidget().restoreState(tabState))
			return false;

		return true;
	}

public:

	void loadPage(QString page)
	{
		QUrl url = guessUrlFromString(page);
		loadUrl(url);
	}

	void slotHome()
	{
		QSettings settings;
		settings.beginGroup(QLatin1String("MainWindow"));
		QString home = settings.value(QLatin1String("home"), QLatin1String("http://qtsoftware.com/")).toString();
		loadPage(home);
	}

protected:

	void closeEvent(QCloseEvent event)
	{
		if (m_tabWidget.count() > 1) {
			int ret = QMessageBox.warning(this, QString(),
				   tr("Are you sure you want to close the window?"
				      "  There are %1 tab open").arg(m_tabWidget.count()),
				   QMessageBox.Yes | QMessageBox.No,
				   QMessageBox.No);
			if (ret == QMessageBox.No) {
				event.ignore();
				return;
			}
		}
		event.accept();
		deleteLater();
	}

private:

	void save()
	{
		BrowserApplication.instance().saveSession();

		QSettings settings;
		settings.beginGroup(QLatin1String("BrowserMainWindow"));
		QByteArray data = saveState(false);
		settings.setValue(QLatin1String("defaultState"), data);
		settings.endGroup();
	}

	void slotLoadProgress(int progress)
	{
		if (progress < 100 && progress > 0) {
			m_chaseWidget.setAnimated(true);
			m_stopReload.triggered.disconnect(&m_reload.trigger);
			if (m_stopIcon.isNull())
				m_stopIcon = style().standardIcon(QStyle.SP_BrowserStop);
			m_stopReload.setIcon(m_stopIcon);
			m_stopReload.triggered.connect(&m_stop.trigger);
			m_stopReload.setToolTip(tr("Stop loading the current page"));
		} else {
			m_chaseWidget.setAnimated(false);
			m_stopReload.triggered.disconnect(m_stop.trigger);
			m_stopReload.setIcon(m_reloadIcon);
			m_stopReload.triggered.connect(&m_reload.trigger);
			m_stopReload.setToolTip(tr("Reload the current page"));
		}
	}

	void slotUpdateStatusbar(QString string)
	{
		statusBar().showMessage(string, 2000);
	}

	void slotUpdateWindowTitle(QString title = QString())
	{
		if (title.isEmpty()) {
			setWindowTitle(tr("Qt Demo Browser"));
		} else {
			version(Q_WS_MAC)
			{
				setWindowTitle(title);
			} else {
				setWindowTitle(tr("%1 - Qt Demo Browser", "Page title and Browser name").arg(title));
			}
		}
	}

	void loadUrl(QUrl url)
	{
		if (!currentTab() || !url.isValid())
			return;

			m_tabWidget.currentLineEdit().setText(QString.fromUtf8(url.toEncoded()));
			m_tabWidget.loadUrlInCurrentTab(url);
	}

	void slotPreferences()
	{
		SettingsDialog s = new SettingsDialog(this);
		s.show();
	}

	void slotFileNew()
	{
		BrowserApplication.instance().newMainWindow();
		BrowserMainWindow mw = BrowserApplication.instance().mainWindow();
		mw.slotHome();
	}

	void slotFileOpen()
	{
		QString file = QFileDialog.getOpenFileName(this, tr("Open Web Resource"), QString(),
		tr("Web Resources (*.html *.htm *.svg *.png *.gif *.svgz);;All files (*.*)"));

		if (file.isEmpty())
			return;

		loadPage(file);
	}

	void slotFilePrintPreview()
	{
		version(QT_NO_PRINTER)
		{
			if (!currentTab())
				return;
			QPrintPreviewDialog dialog = new QPrintPreviewDialog(this);
			dialog.paintRequested.connect(&currentTab.print);
			dialog.exec();
		}
	}

	void slotFilePrint()
	{
		if (!currentTab())
			return;
		printRequested(currentTab().page().mainFrame());
	}

	void slotPrivateBrowsing()
	{
		QWebSettings settings = QWebSettings.globalSettings();
		bool pb = settings.testAttribute(QWebSettings.PrivateBrowsingEnabled);
		if (!pb) {
			QString title = tr("Are you sure you want to turn on private browsing?");
			QString text = tr("<b>%1</b><br><br>When private browsing in turned on,"
			" webpages are not added to the history,"
			" items are automatically removed from the Downloads window,"
			" new cookies are not stored, current cookies can't be accessed,"
			" site icons wont be stored, session wont be saved, "
			" and searches are not addded to the pop-up menu in the Google search box."
			"  Until you close the window, you can still click the Back and Forward buttons"
			" to return to the webpages you have opened.").arg(title);

			QMessageBox.StandardButton button = QMessageBox.question(this, QString(), text,
			       QMessageBox.Ok | QMessageBox.Cancel,
			       QMessageBox.Ok);
			if (button == QMessageBox.Ok) {
				settings.setAttribute(QWebSettings.PrivateBrowsingEnabled, true);
			}
		} else {
			settings.setAttribute(QWebSettings.PrivateBrowsingEnabled, false);

			BrowserMainWindow[] windows = BrowserApplication.instance().mainWindows();
			for (int i = 0; i < windows.count(); ++i) {
				BrowserMainWindow window = windows.at(i);
				window.m_lastSearch = null; //QString::null
				window.tabWidget().clear();
			}
		}
	}

	void slotFileSaveAs()
	{
		BrowserApplication.downloadManager().download(currentTab().url(), true);
	}

	void slotEditFind()
	{
		if (!currentTab())
			return;
		bool ok;
		QString search = QInputDialog.getText(this, tr("Find"), tr("Text:"), QLineEdit.Normal, m_lastSearch, &ok);
		if (ok && !search.isEmpty()) {
			m_lastSearch = search;
			if (!currentTab().findText(m_lastSearch))
				slotUpdateStatusbar(tr("\"%1\" not found.").arg(m_lastSearch));
		}
	}

	void slotEditFindNext()
	{
		if (!currentTab() && !m_lastSearch.isEmpty())
			return;
		currentTab().findText(m_lastSearch);
	}

	void slotEditFindPrevious()
	{
		if (!currentTab() && !m_lastSearch.isEmpty())
			return;
		currentTab().findText(m_lastSearch, QWebPage.FindBackward);
	}

	void slotShowBookmarksDialog()
	{
		BookmarksDialog dialog = new BookmarksDialog(this);
		dialog.openUrl.connect(&m_tabWidget.loadUrlInCurrentTab);
		dialog.show();
	}

	void slotAddBookmark()
	{
		WebView webView = currentTab();
		QString url = webView.url().toString();
		QString title = webView.title();
		AddBookmarkDialog dialog(url, title);
		dialog.exec();
	}

	void slotViewZoomIn()
	{
		if (!currentTab())
			return;
		currentTab().setZoomFactor(currentTab().zoomFactor() + 0.1);
	}

	void BslotViewZoomOut()
	{
		if (!currentTab())
			return;
		currentTab().setZoomFactor(currentTab().zoomFactor() - 0.1);
	}

	void slotViewResetZoom()
	{
		if (!currentTab())
			return;
		currentTab().setZoomFactor(1.0);
	}

	void slotViewZoomTextOnly(bool enable)
	{
		if (!currentTab())
			return;
		currentTab().page().settings().setAttribute(QWebSettings.ZoomTextOnly, enable);
	}

	void slotViewToolbar()
	{
		if (m_navigationBar.isVisible()) {
			updateToolbarActionText(false);
			m_navigationBar.close();
		} else {
			updateToolbarActionText(true);
			m_navigationBar.show();
		}
		m_autoSaver.changeOccurred();
	}


	void slotViewBookmarksBar()
	{
		if (m_bookmarksToolbar.isVisible()) {
			updateBookmarksToolbarActionText(false);
			m_bookmarksToolbar.close();
		} else {
			updateBookmarksToolbarActionText(true);
			m_bookmarksToolbar.show();
		}
		m_autoSaver.changeOccurred();
	}

	void slotViewStatusbar()
	{
		if (statusBar().isVisible()) {
			updateStatusbarActionText(false);
			statusBar().close();
		} else {
			updateStatusbarActionText(true);
			statusBar().show();
		}
		m_autoSaver.changeOccurred();
	}

	void slotViewPageSource()
	{
		if (!currentTab())
			return;

		QString markup = currentTab().page().mainFrame().toHtml();
		QPlainTextEdit view = new QPlainTextEdit(markup);
		view.setWindowTitle(tr("Page Source of %1").arg(currentTab().title()));
		view.setMinimumWidth(640);
		view.setAttribute(Qt.WA_DeleteOnClose);
		view.show();
	}


	void slotViewFullScreen(bool makeFullScreen)
	{
		if (makeFullScreen) {
			showFullScreen();
		} else {
			if (isMinimized())
				showMinimized();
			else if (isMaximized())
				showMaximized();
			else showNormal();
		}
	}

	void slotWebSearch()
	{
		m_toolbarSearch.lineEdit().selectAll();
		m_toolbarSearch.lineEdit().setFocus();
	}

	void slotToggleInspector(bool enable)
	{
		QWebSettings.globalSettings().setAttribute(QWebSettings.DeveloperExtrasEnabled, enable);
		if (enable) {
			int result = QMessageBox.question(this, tr("Web Inspector"),
						   tr("The web inspector will only work correctly for pages that were loaded after enabling.\n"
						   "Do you want to reload all pages?"),
						   QMessageBox.Yes | QMessageBox.No);
			if (result == QMessageBox.Yes) {
				m_tabWidget.reloadAllTabs();
			}
		}
	}

	void slotAboutApplication()
	{
		QMessageBox.about(this, tr("About"), tr(
			"Version %1"
			"<p>This demo demonstrates Qt's "
			"webkit facilities in action, providing an example "
			"browser for you to experiment with.<p>"
			"<p>QtWebKit is based on the Open Source WebKit Project developed at <a href=\"http://webkit.org/\">http://webkit.org/</a>."
			).arg(QCoreApplication.applicationVersion()));
	}

	void slotDownloadManager()
	{
		BrowserApplication.downloadManager().show();
	}

	void slotSelectLineEdit()
	{
		m_tabWidget.currentLineEdit().selectAll();
		m_tabWidget.currentLineEdit().setFocus();
	}

	void slotAboutToShowBackMenu()
	{
		m_historyBackMenu.clear();
		if (!currentTab())
			return;
		QWebHistory history = currentTab().history();
		int historyCount = history.count();
		for (int i = history.backItems(historyCount).count() - 1; i >= 0; --i) {
			QWebHistoryItem item = history.backItems(history.count()).at(i);
			QAction action = new QAction(this);
			action.setData(-1*(historyCount-i-1));
			QIcon icon = BrowserApplication.instance().icon(item.url());
			action.setIcon(icon);
			action.setText(item.title());
			m_historyBackMenu.addAction(action);
		}
	}

	void slotAboutToShowForwardMenu()
	{
		m_historyForwardMenu.clear();
		if (!currentTab())
			return;
		QWebHistory history = currentTab().history();
		int historyCount = history.count();
		for (int i = 0; i < history.forwardItems(history.count()).count(); ++i) {
			QWebHistoryItem item = history.forwardItems(historyCount).at(i);
			QAction action = new QAction(this);
			action.setData(historyCount-i);
			QIcon icon = BrowserApplication.instance().icon(item.url());
			action.setIcon(icon);
			action.setText(item.title());
			m_historyForwardMenu.addAction(action);
		}
	}

	void slotAboutToShowWindowMenu()
	{
		m_windowMenu.clear();
		m_windowMenu.addAction(m_tabWidget.nextTabAction());
		m_windowMenu.addAction(m_tabWidget.previousTabAction());
		m_windowMenu.addSeparator();
		m_windowMenu.addAction(tr("Downloads"), this, SLOT(slotDownloadManager()), QKeySequence(tr("Alt+Ctrl+L", "Download Manager")));

		m_windowMenu.addSeparator();
		BrowserMainWindow[] windows = BrowserApplication.instance().mainWindows();
		for (int i = 0; i < windows.count(); ++i) {
			BrowserMainWindow window = windows.at(i);
			QAction action = m_windowMenu.addAction(window.windowTitle(), this, SLOT(slotShowWindow()));
			action.setData(i);
			action.setCheckable(true);
			if (window == this)
			action.setChecked(true);
		}
	}

	void slotOpenActionUrl(QAction action)
	{
		int offset = action.data().toInt();
		QWebHistory history = currentTab().history();
		if (offset < 0)
			history.goToItem(history.backItems(-1*offset).first()); // back
		else if (offset > 0)
			history.goToItem(history.forwardItems(history.count() - offset + 1).back()); // forward
	}

	void slotShowWindow()
	{
		if (QAction action = cast(QAction) sender()) {
			QVariant v = action.data();
			if (v.canConvert!(int)()) {
				int offset = cast(int) v;
				BrowserMainWindow[] windows = BrowserApplication.instance().mainWindows();
				windows.at(offset).activateWindow();
				windows.at(offset).currentTab().setFocus();
			}
		}
	}

	void slotSwapFocus()
	{
		if (currentTab().hasFocus())
			m_tabWidget.currentLineEdit().setFocus();
		else
			currentTab().setFocus();
	}

	void printRequested(QWebFrame frame)
	{
		version(QT_NO_PRINTER)
		{
			QPrinter printer;
			QPrintDialog dialog = new QPrintDialog(&printer, this);
			dialog.setWindowTitle(tr("Print Document"));
			if (dialog.exec() != QDialog.Accepted)
				return;
			frame.print(&printer);
		}
	}

	void geometryChangeRequested(QRect geometry)
	{
		setGeometry(geometry);
	}

	void updateToolbarActionText(bool visible)
	{
		m_viewToolbar.setText(!visible ? tr("Show Toolbar") : tr("Hide Toolbar"));
	}
    
	void updateBookmarksToolbarActionText(bool visible)
	{
		m_viewBookmarkBar.setText(!visible ? tr("Show Bookmarks bar") : tr("Hide Bookmarks bar"));
	}

private:

	void loadDefaultState()
	{
		QSettings settings;
		settings.beginGroup(QLatin1String("BrowserMainWindow"));
		QByteArray data = settings.value(QLatin1String("defaultState")).toByteArray();
		restoreState(data);
		settings.endGroup();
	}

	void setupMenu()
	{
		new QShortcut(QKeySequence(Qt.Key_F6), this, SLOT(slotSwapFocus()));

		// File
		QMenu fileMenu = menuBar().addMenu(tr("&File"));

		fileMenu.addAction(tr("&New Window"), this, SLOT(slotFileNew()), QKeySequence.New);
		fileMenu.addAction(m_tabWidget.newTabAction());
		fileMenu.addAction(tr("&Open File..."), this, SLOT(slotFileOpen()), QKeySequence.Open);
		fileMenu.addAction(tr("Open &Location..."), this, SLOT(slotSelectLineEdit()), QKeySequence(Qt.ControlModifier + Qt.Key_L));
		fileMenu.addSeparator();
		fileMenu.addAction(m_tabWidget.closeTabAction());
		fileMenu.addSeparator();
		fileMenu.addAction(tr("&Save As..."), this,  SLOT(slotFileSaveAs()), QKeySequence(QKeySequence.Save));
		fileMenu.addSeparator();
		BookmarksManager bookmarksManager = BrowserApplication.bookmarksManager();
		fileMenu.addAction(tr("&Import Bookmarks..."), bookmarksManager, SLOT(importBookmarks()));
		fileMenu.addAction(tr("&Export Bookmarks..."), bookmarksManager, SLOT(exportBookmarks()));
		fileMenu.addSeparator();
		fileMenu.addAction(tr("P&rint Preview..."), this, SLOT(slotFilePrintPreview()));
		fileMenu.addAction(tr("&Print..."), this, SLOT(slotFilePrint()), QKeySequence.Print);
		fileMenu.addSeparator();
		QAction action = fileMenu.addAction(tr("Private &Browsing..."), this, SLOT(slotPrivateBrowsing()));
		action.setCheckable(true);
		fileMenu.addSeparator();

		version(Q_WS_MAC) {
			fileMenu.addAction(tr("&Quit"), BrowserApplication.instance(), SLOT(quitBrowser()), QKeySequence(Qt.CTRL | Qt.Key_Q));
		} else {
			fileMenu.addAction(tr("&Quit"), this, SLOT(close()), QKeySequence(Qt.CTRL | Qt.Key_Q));
		}

		// Edit
		QMenu editMenu = menuBar().addMenu(tr("&Edit"));
		QAction m_undo = editMenu.addAction(tr("&Undo"));
		m_undo.setShortcuts(QKeySequence.Undo);
		m_tabWidget.addWebAction(m_undo, QWebPage.Undo);
		QAction m_redo = editMenu.addAction(tr("&Redo"));
		m_redo.setShortcuts(QKeySequence.Redo);
		m_tabWidget.addWebAction(m_redo, QWebPage.Redo);
		editMenu.addSeparator();
		QAction m_cut = editMenu.addAction(tr("Cu&t"));
		m_cut.setShortcuts(QKeySequence.Cut);
		m_tabWidget.addWebAction(m_cut, QWebPage.Cut);
		QAction m_copy = editMenu.addAction(tr("&Copy"));
		m_copy.setShortcuts(QKeySequence.Copy);
		m_tabWidget.addWebAction(m_copy, QWebPage.Copy);
		QAction m_paste = editMenu.addAction(tr("&Paste"));
		m_paste.setShortcuts(QKeySequence.Paste);
		m_tabWidget.addWebAction(m_paste, QWebPage.Paste);
		editMenu.addSeparator();

		QAction m_find = editMenu.addAction(tr("&Find"));
		m_find.setShortcuts(QKeySequence.Find);
		m_find.triggered().connect(&this.slotEditFind);
		new QShortcut(QKeySequence(Qt.Key_Slash), this, SLOT(slotEditFind()));

		QAction m_findNext = editMenu.addAction(tr("&Find Next"));
		m_findNext.setShortcuts(QKeySequence.FindNext);
		m_findNext.triggered().connect(&this.slotEditFindNext);

		QAction m_findPrevious = editMenu.addAction(tr("&Find Previous"));
		m_findPrevious.setShortcuts(QKeySequence.FindPrevious);
		m_findPrevious.triggered().connect(&this.slotEditFindPrevious);

		editMenu.addSeparator();
		editMenu.addAction(tr("&Preferences"), this, SLOT(slotPreferences()), tr("Ctrl+,"));

		// View
		QMenu viewMenu = menuBar().addMenu(tr("&View"));

		m_viewBookmarkBar = new QAction(this);
		updateBookmarksToolbarActionText(true);
		m_viewBookmarkBar.setShortcut(tr("Shift+Ctrl+B"));
		m_viewBookmarkBar.triggered().connect(&this.slotViewBookmarksBar);
		viewMenu.addAction(m_viewBookmarkBar);

		m_viewToolbar = new QAction(this);
		updateToolbarActionText(true);
		m_viewToolbar.setShortcut(tr("Ctrl+|"));
		m_viewToolbar.triggered().connect(&this.slotViewToolbar);
		viewMenu.addAction(m_viewToolbar);

		m_viewStatusbar = new QAction(this);
		updateStatusbarActionText(true);
		m_viewStatusbar.setShortcut(tr("Ctrl+/"));
		m_viewStatusbar.triggered().connect(&this.slotViewStatusbar);
		viewMenu.addAction(m_viewStatusbar);

		viewMenu.addSeparator();

		m_stop = viewMenu.addAction(tr("&Stop"));
		QKeySequence[] shortcuts;
		shortcuts.append(QKeySequence(Qt.CTRL | Qt.Key_Period));
		shortcuts.append(Qt.Key_Escape);
		m_stop.setShortcuts(shortcuts);
		m_tabWidget.addWebAction(m_stop, QWebPage.Stop);

		m_reload = viewMenu.addAction(tr("Reload Page"));
		m_reload.setShortcuts(QKeySequence.Refresh);
		m_tabWidget.addWebAction(m_reload, QWebPage.Reload);

		viewMenu.addAction(tr("Zoom &In"), this, SLOT(slotViewZoomIn()), QKeySequence(Qt.CTRL | Qt.Key_Plus));
		viewMenu.addAction(tr("Zoom &Out"), this, SLOT(slotViewZoomOut()), QKeySequence(Qt.CTRL | Qt.Key_Minus));
		viewMenu.addAction(tr("Reset &Zoom"), this, SLOT(slotViewResetZoom()), QKeySequence(Qt.CTRL | Qt.Key_0));
		QAction zoomTextOnlyAction = viewMenu.addAction(tr("Zoom &Text Only"));
		zoomTextOnlyAction.toggled().connect(&this.slotViewZoomTextOnly);
		zoomTextOnlyAction.setCheckable(true);
		zoomTextOnlyAction.setChecked(false);

		viewMenu.addSeparator();
		viewMenu.addAction(tr("Page S&ource"), this, SLOT(slotViewPageSource()), tr("Ctrl+Alt+U"));
		QAction a = viewMenu.addAction(tr("&Full Screen"), this, SLOT(slotViewFullScreen),  Qt.Key_F11);
		a.setCheckable(true);

		// History
		HistoryMenu historyMenu = new HistoryMenu(this);
		historyMenu.openUrl.connect(&m_tabWidget.loadUrlInCurrentTab);
		historyMenu.hovered.connect(&this.slotUpdateStatusbar);
		historyMenu.setTitle(tr("Hi&story"));
		menuBar().addMenu(historyMenu);
		QAction[] historyActions;

		m_historyBack = new QAction(tr("Back"), this);
		m_tabWidget.addWebAction(m_historyBack, QWebPage.Back);
		m_historyBack.setShortcuts(QKeySequence.Back);
		m_historyBack.setIconVisibleInMenu(false);

		m_historyForward = new QAction(tr("Forward"), this);
		m_tabWidget.addWebAction(m_historyForward, QWebPage.Forward);
		m_historyForward.setShortcuts(QKeySequence.Forward);
		m_historyForward.setIconVisibleInMenu(false);

		QAction m_historyHome = new QAction(tr("Home"), this);
		m_historyHome.triggered().connect(&this.slotHome);
		m_historyHome.setShortcut(QKeySequence(Qt.CTRL | Qt.SHIFT | Qt.Key_H));

		m_restoreLastSession = new QAction(tr("Restore Last Session"), this);
		m_restoreLastSession.triggered().connect(BrowserApplication.instance().restoreLastSession);
		m_restoreLastSession.setEnabled(BrowserApplication.instance().canRestoreSession());

		historyActions.append(m_historyBack);
		historyActions.append(m_historyForward);
		historyActions.append(m_historyHome);
		historyActions.append(m_tabWidget.recentlyClosedTabsAction());
		historyActions.append(m_restoreLastSession);
		historyMenu.setInitialActions(historyActions);

		// Bookmarks
		BookmarksMenu bookmarksMenu = new BookmarksMenu(this);
		bookmarksMenu.openUrl.connect(&m_tabWidget.loadUrlInCurrentTab);
		bookmarksMenu.hovered.connect(&this.slotUpdateStatusbar);
		bookmarksMenu.setTitle(tr("&Bookmarks"));
		menuBar().addMenu(bookmarksMenu);

		QAction[] bookmarksActions;

		QAction showAllBookmarksAction = new QAction(tr("Show All Bookmarks"), this);
		showAllBookmarksAction.triggered().connect(&this.slotShowBookmarksDialog);
		m_addBookmark = new QAction(QIcon(QLatin1String(":addbookmark.png")), tr("Add Bookmark..."), this);
		m_addBookmark.setIconVisibleInMenu(false);

		m_addBookmark.triggered().connect(&this.slotAddBookmark);
		m_addBookmark.setShortcut(QKeySequence(Qt.CTRL | Qt.Key_D));

		bookmarksActions.append(showAllBookmarksAction);
		bookmarksActions.append(m_addBookmark);
		bookmarksMenu.setInitialActions(bookmarksActions);

		// Window
		m_windowMenu = menuBar().addMenu(tr("&Window"));
		m_windowMenu.aboutToShow().connect(&this.slotAboutToShowWindowMenu);
		slotAboutToShowWindowMenu();

		QMenu toolsMenu = menuBar().addMenu(tr("&Tools"));
		toolsMenu.addAction(tr("Web &Search"), this, SLOT(slotWebSearch()), QKeySequence(tr("Ctrl+K", "Web Search")));
		version(Q_CC_MINGW)
		{
			a = toolsMenu.addAction(tr("Enable Web &Inspector"), this, SLOT(slotToggleInspector));
			a.setCheckable(true);
		}

		QMenu helpMenu = menuBar().addMenu(tr("&Help"));
		helpMenu.addAction(tr("About &Qt"), qApp, SLOT(aboutQt()));
		helpMenu.addAction(tr("About &Demo Browser"), this, SLOT(slotAboutApplication()));
	}

	void setupToolBar()
	{
		setUnifiedTitleAndToolBarOnMac(true);
		m_navigationBar = addToolBar(tr("Navigation"));
		m_navigationBar.toggleViewAction().toggled.connect(&this.updateToolbarActionText);

		m_historyBack.setIcon(style().standardIcon(QStyle.SP_ArrowBack, 0, this));
		m_historyBackMenu = new QMenu(this);
		m_historyBack.setMenu(m_historyBackMenu);
		m_historyBackMenu.aboutToShow().connect(&this.slotAboutToShowBackMenu);
		m_historyBackMenu.triggered.connect(&this.slotOpenActionUrl);
		m_navigationBar.addAction(m_historyBack);

		m_historyForward.setIcon(style().standardIcon(QStyle.SP_ArrowForward, 0, this));
		m_historyForwardMenu = new QMenu(this);
		m_historyForwardMenu.aboutToShow.connect(&this.slotAboutToShowForwardMenu);
		m_historyForwardMenu.triggered.connect(&this.slotOpenActionUrl);
		m_historyForward.setMenu(m_historyForwardMenu);
		m_navigationBar.addAction(m_historyForward);

		m_stopReload = new QAction(this);
		m_reloadIcon = style().standardIcon(QStyle.SP_BrowserReload);
		m_stopReload.setIcon(m_reloadIcon);

		m_navigationBar.addAction(m_stopReload);

		m_navigationBar.addWidget(m_tabWidget.lineEditStack());

		m_toolbarSearch = new ToolbarSearch(m_navigationBar);
		m_navigationBar.addWidget(m_toolbarSearch);
		m_toolbarSearch.search.connect(&loadUrl);

		m_chaseWidget = new ChaseWidget(this);
		m_navigationBar.addWidget(m_chaseWidget);
	}

	void updateStatusbarActionText(bool visible)
	{
		m_viewStatusbar.setText(!visible ? tr("Show Status Bar") : tr("Hide Status Bar"));
	}

private:

	QToolBar m_navigationBar;
	ToolbarSearch m_toolbarSearch;
	BookmarksToolBar m_bookmarksToolbar;
	ChaseWidget m_chaseWidget;
	TabWidget m_tabWidget;
	AutoSaver m_autoSaver;

	QAction m_historyBack;
	QMenu m_historyBackMenu;
	QAction m_historyForward;
	QMenu m_historyForwardMenu;
	QMenu m_windowMenu;

	QAction m_stop;
	QAction m_reload;
	QAction m_stopReload;
	QAction m_viewToolbar;
	QAction m_viewBookmarkBar;
	QAction m_viewStatusbar;
	QAction m_restoreLastSession;
	QAction m_addBookmark;

	QIcon m_reloadIcon;
	QIcon m_stopIcon;

	QString m_lastSearch;
}