/*
* Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
* Copyright (C) 2010 University of Szeged
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "BrowserWindow.h"
#include "UrlLoader.h"
#include "qwkpreferences.h"
static QWKPage* newPageFunction(QWKPage* page)
{
BrowserWindow* window = new BrowserWindow(page->context());
return window->page();
}
QVector<qreal> BrowserWindow::m_zoomLevels;
BrowserWindow::BrowserWindow(QWKContext* context, WindowOptions* options)
: m_isZoomTextOnly(false)
, m_currentZoom(1)
, m_urlLoader(0)
, m_context(context)
{
if (options)
m_windowOptions = *options;
else {
WindowOptions tmpOptions;
m_windowOptions = tmpOptions;
}
if (m_windowOptions.useTiledBackingStore)
m_browser = new BrowserView(QGraphicsWKView::Tiled, context);
else
m_browser = new BrowserView(QGraphicsWKView::Simple, context);
setAttribute(Qt::WA_DeleteOnClose);
connect(m_browser->view(), SIGNAL(loadProgress(int)), SLOT(loadProgress(int)));
connect(m_browser->view(), SIGNAL(titleChanged(const QString&)), SLOT(setWindowTitle(const QString&)));
connect(m_browser->view(), SIGNAL(urlChanged(const QUrl&)), SLOT(urlChanged(const QUrl&)));
if (m_windowOptions.printLoadedUrls)
connect(page(), SIGNAL(urlChanged(QUrl)), this, SLOT(printURL(QUrl)));
this->setCentralWidget(m_browser);
m_browser->setFocus(Qt::OtherFocusReason);
QMenu* fileMenu = menuBar()->addMenu("&File");
fileMenu->addAction("New Window", this, SLOT(newWindow()), QKeySequence::New);
fileMenu->addAction("Open File", this, SLOT(openFile()), QKeySequence::Open);
fileMenu->addSeparator();
fileMenu->addAction("Quit", this, SLOT(close()));
QMenu* viewMenu = menuBar()->addMenu("&View");
viewMenu->addAction(page()->action(QWKPage::Stop));
viewMenu->addAction(page()->action(QWKPage::Reload));
viewMenu->addSeparator();
QAction* zoomIn = viewMenu->addAction("Zoom &In", this, SLOT(zoomIn()));
QAction* zoomOut = viewMenu->addAction("Zoom &Out", this, SLOT(zoomOut()));
QAction* resetZoom = viewMenu->addAction("Reset Zoom", this, SLOT(resetZoom()));
QAction* zoomText = viewMenu->addAction("Zoom Text Only", this, SLOT(toggleZoomTextOnly(bool)));
zoomText->setCheckable(true);
zoomText->setChecked(false);
viewMenu->addSeparator();
viewMenu->addAction("Take Screen Shot...", this, SLOT(screenshot()));
zoomIn->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_Plus));
zoomOut->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_Minus));
resetZoom->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_0));
QMenu* windowMenu = menuBar()->addMenu("&Window");
QAction* toggleFullScreen = windowMenu->addAction("Toggle FullScreen", this, SIGNAL(enteredFullScreenMode(bool)));
toggleFullScreen->setShortcut(Qt::Key_F11);
toggleFullScreen->setCheckable(true);
toggleFullScreen->setChecked(false);
// When exit fullscreen mode by clicking on the exit area (bottom right corner) we must
// uncheck the Toggle FullScreen action.
toggleFullScreen->connect(this, SIGNAL(enteredFullScreenMode(bool)), SLOT(setChecked(bool)));
connect(this, SIGNAL(enteredFullScreenMode(bool)), this, SLOT(toggleFullScreenMode(bool)));
QMenu* toolsMenu = menuBar()->addMenu("&Develop");
QAction* toggleFrameFlattening = toolsMenu->addAction("Toggle Frame Flattening", this, SLOT(toggleFrameFlattening(bool)));
toggleFrameFlattening->setCheckable(true);
toggleFrameFlattening->setChecked(false);
toolsMenu->addSeparator();
toolsMenu->addAction("Change User Agent", this, SLOT(showUserAgentDialog()));
toolsMenu->addSeparator();
toolsMenu->addAction("Load URLs from file", this, SLOT(loadURLListFromFile()));
QMenu* settingsMenu = menuBar()->addMenu("&Settings");
QAction* toggleAutoLoadImages = settingsMenu->addAction("Disable Auto Load Images", this, SLOT(toggleAutoLoadImages(bool)));
toggleAutoLoadImages->setCheckable(true);
toggleAutoLoadImages->setChecked(false);
QAction* toggleDisableJavaScript = settingsMenu->addAction("Disable JavaScript", this, SLOT(toggleDisableJavaScript(bool)));
toggleDisableJavaScript->setCheckable(true);
toggleDisableJavaScript->setChecked(false);
m_addressBar = new QLineEdit();
connect(m_addressBar, SIGNAL(returnPressed()), SLOT(changeLocation()));
QToolBar* bar = addToolBar("Navigation");
bar->addAction(page()->action(QWKPage::Back));
bar->addAction(page()->action(QWKPage::Forward));
bar->addAction(page()->action(QWKPage::Reload));
bar->addAction(page()->action(QWKPage::Stop));
bar->addWidget(m_addressBar);
QShortcut* selectAddressBar = new QShortcut(Qt::CTRL | Qt::Key_L, this);
connect(selectAddressBar, SIGNAL(activated()), this, SLOT(openLocation()));
page()->setCreateNewPageFunction(newPageFunction);
// the zoom values are chosen to be like in Mozilla Firefox 3
if (!m_zoomLevels.count()) {
m_zoomLevels << 0.3 << 0.5 << 0.67 << 0.8 << 0.9;
m_zoomLevels << 1;
m_zoomLevels << 1.1 << 1.2 << 1.33 << 1.5 << 1.7 << 2 << 2.4 << 3;
}
if (m_windowOptions.startMaximized)
setWindowState(windowState() | Qt::WindowMaximized);
else
resize(800, 600);
show();
}
void BrowserWindow::load(const QString& url)
{
m_addressBar->setText(url);
m_browser->load(url);
}
QWKPage* BrowserWindow::page()
{
return m_browser->view()->page();
}
BrowserWindow* BrowserWindow::newWindow(const QString& url)
{
BrowserWindow* window;
if (m_windowOptions.useSeparateWebProcessPerWindow) {
QWKContext* context = new QWKContext();
window = new BrowserWindow(context);
context->setParent(window);
} else
window = new BrowserWindow(m_context);
window->load(url);
return window;
}
void BrowserWindow::openLocation()
{
m_addressBar->selectAll();
m_addressBar->setFocus();
}
void BrowserWindow::changeLocation()
{
QString string = m_addressBar->text();
m_browser->load(string);
}
void BrowserWindow::loadProgress(int progress)
{
QColor backgroundColor = QApplication::palette().color(QPalette::Base);
QColor progressColor = QColor(120, 180, 240);
QPalette pallete = m_addressBar->palette();
if (progress <= 0 || progress >= 100)
pallete.setBrush(QPalette::Base, backgroundColor);
else {
QLinearGradient gradient(0, 0, width(), 0);
gradient.setColorAt(0, progressColor);
gradient.setColorAt(((double) progress) / 100, progressColor);
if (progress != 100)
gradient.setColorAt((double) progress / 100 + 0.001, backgroundColor);
pallete.setBrush(QPalette::Base, gradient);
}
m_addressBar->setPalette(pallete);
}
void BrowserWindow::urlChanged(const QUrl& url)
{
m_addressBar->setText(url.toString());
m_browser->setFocus();
m_browser->view()->setFocus();
}
void BrowserWindow::openFile()
{
#ifndef QT_NO_FILEDIALOG
static const QString filter("HTML Files (*.htm *.html *.xhtml);;Text Files (*.txt);;Image Files (*.gif *.jpg *.png);;SVG Files (*.svg);;All Files (*)");
QFileDialog fileDialog(this, tr("Open"), QString(), filter);
fileDialog.setAcceptMode(QFileDialog::AcceptOpen);
fileDialog.setFileMode(QFileDialog::ExistingFile);
fileDialog.setOptions(QFileDialog::ReadOnly);
if (fileDialog.exec()) {
QString selectedFile = fileDialog.selectedFiles()[0];
if (!selectedFile.isEmpty())
load(selectedFile);
}
#endif
}
void BrowserWindow::screenshot()
{
QPixmap pixmap = QPixmap::grabWidget(m_browser);
QLabel* label = 0;
#if !defined(Q_OS_SYMBIAN)
label = new QLabel;
label->setAttribute(Qt::WA_DeleteOnClose);
label->setWindowTitle("Screenshot - Preview");
label->setPixmap(pixmap);
label->show();
#endif
#ifndef QT_NO_FILEDIALOG
QString fileName = QFileDialog::getSaveFileName(label, "Screenshot", QString(), QString("PNG File (.png)"));
if (!fileName.isEmpty()) {
QRegExp rx("*.png");
rx.setCaseSensitivity(Qt::CaseInsensitive);
rx.setPatternSyntax(QRegExp::Wildcard);
if (!rx.exactMatch(fileName))
fileName += ".png";
pixmap.save(fileName, "png");
if (label)
label->setWindowTitle(QString("Screenshot - Saved at %1").arg(fileName));
}
#endif
}
void BrowserWindow::zoomIn()
{
if (m_isZoomTextOnly)
m_currentZoom = page()->textZoomFactor();
else
m_currentZoom = page()->pageZoomFactor();
int i = m_zoomLevels.indexOf(m_currentZoom);
Q_ASSERT(i >= 0);
if (i < m_zoomLevels.count() - 1)
m_currentZoom = m_zoomLevels[i + 1];
applyZoom();
}
void BrowserWindow::zoomOut()
{
if (m_isZoomTextOnly)
m_currentZoom = page()->textZoomFactor();
else
m_currentZoom = page()->pageZoomFactor();
int i = m_zoomLevels.indexOf(m_currentZoom);
Q_ASSERT(i >= 0);
if (i > 0)
m_currentZoom = m_zoomLevels[i - 1];
applyZoom();
}
void BrowserWindow::resetZoom()
{
m_currentZoom = 1;
applyZoom();
}
void BrowserWindow::toggleZoomTextOnly(bool b)
{
m_isZoomTextOnly = b;
}
void BrowserWindow::toggleFullScreenMode(bool enable)
{
bool alreadyEnabled = windowState() & Qt::WindowFullScreen;
if (enable ^ alreadyEnabled)
setWindowState(windowState() ^ Qt::WindowFullScreen);
}
void BrowserWindow::toggleFrameFlattening(bool toggle)
{
page()->preferences()->setAttribute(QWKPreferences::FrameFlatteningEnabled, toggle);
}
void BrowserWindow::showUserAgentDialog()
{
updateUserAgentList();
QDialog dialog(this);
dialog.setWindowTitle("Change User Agent");
dialog.resize(size().width() * 0.7, dialog.size().height());
QVBoxLayout* layout = new QVBoxLayout(&dialog);
dialog.setLayout(layout);
QComboBox* combo = new QComboBox(&dialog);
combo->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLength);
combo->setEditable(true);
combo->insertItems(0, m_userAgentList);
layout->addWidget(combo);
int index = combo->findText(page()->customUserAgent());
combo->setCurrentIndex(index);
QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel
, Qt::Horizontal, &dialog);
connect(buttonBox, SIGNAL(accepted()), &dialog, SLOT(accept()));
connect(buttonBox, SIGNAL(rejected()), &dialog, SLOT(reject()));
layout->addWidget(buttonBox);
if (dialog.exec() && !combo->currentText().isEmpty())
page()->setCustomUserAgent(combo->currentText());
}
void BrowserWindow::loadURLListFromFile()
{
QString selectedFile;
#ifndef QT_NO_FILEDIALOG
selectedFile = QFileDialog::getOpenFileName(this, tr("Load URL list from file")
, QString(), tr("Text Files (*.txt);;All Files (*)"));
#endif
if (selectedFile.isEmpty())
return;
m_urlLoader = new UrlLoader(this, selectedFile, 0, 0);
m_urlLoader->loadNext();
}
void BrowserWindow::printURL(const QUrl& url)
{
QTextStream output(stdout);
output << "Loaded: " << url.toString() << endl;
}
void BrowserWindow::toggleDisableJavaScript(bool enable)
{
page()->preferences()->setAttribute(QWKPreferences::JavascriptEnabled, !enable);
}
void BrowserWindow::toggleAutoLoadImages(bool enable)
{
page()->preferences()->setAttribute(QWKPreferences::AutoLoadImages, !enable);
}
void BrowserWindow::updateUserAgentList()
{
QFile file(":/useragentlist.txt");
if (file.open(QIODevice::ReadOnly)) {
while (!file.atEnd()) {
QString agent = file.readLine().trimmed();
if (!m_userAgentList.contains(agent))
m_userAgentList << agent;
}
file.close();
}
Q_ASSERT(!m_userAgentList.isEmpty());
QWKPage* wkPage = page();
if (!(wkPage->customUserAgent().isEmpty() || m_userAgentList.contains(wkPage->customUserAgent())))
m_userAgentList << wkPage->customUserAgent();
}
void BrowserWindow::applyZoom()
{
if (m_isZoomTextOnly)
page()->setTextZoomFactor(m_currentZoom);
else
page()->setPageZoomFactor(m_currentZoom);
}
BrowserWindow::~BrowserWindow()
{
delete m_urlLoader;
delete m_addressBar;
delete m_browser;
}