1/* 2 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) 3 * Copyright (C) 2010 University of Szeged 4 * 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 24 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#include "BrowserWindow.h" 30 31#include "UrlLoader.h" 32#include "qwkpreferences.h" 33 34static QWKPage* newPageFunction(QWKPage* page) 35{ 36 BrowserWindow* window = new BrowserWindow(page->context()); 37 return window->page(); 38} 39 40QVector<qreal> BrowserWindow::m_zoomLevels; 41 42BrowserWindow::BrowserWindow(QWKContext* context, WindowOptions* options) 43 : m_isZoomTextOnly(false) 44 , m_currentZoom(1) 45 , m_urlLoader(0) 46 , m_context(context) 47{ 48 if (options) 49 m_windowOptions = *options; 50 else { 51 WindowOptions tmpOptions; 52 m_windowOptions = tmpOptions; 53 } 54 55 if (m_windowOptions.useTiledBackingStore) 56 m_browser = new BrowserView(QGraphicsWKView::Tiled, context); 57 else 58 m_browser = new BrowserView(QGraphicsWKView::Simple, context); 59 60 setAttribute(Qt::WA_DeleteOnClose); 61 62 connect(m_browser->view(), SIGNAL(loadProgress(int)), SLOT(loadProgress(int))); 63 connect(m_browser->view(), SIGNAL(titleChanged(const QString&)), SLOT(setWindowTitle(const QString&))); 64 connect(m_browser->view(), SIGNAL(urlChanged(const QUrl&)), SLOT(urlChanged(const QUrl&))); 65 66 if (m_windowOptions.printLoadedUrls) 67 connect(page(), SIGNAL(urlChanged(QUrl)), this, SLOT(printURL(QUrl))); 68 69 this->setCentralWidget(m_browser); 70 m_browser->setFocus(Qt::OtherFocusReason); 71 72 QMenu* fileMenu = menuBar()->addMenu("&File"); 73 fileMenu->addAction("New Window", this, SLOT(newWindow()), QKeySequence::New); 74 fileMenu->addAction("Open File", this, SLOT(openFile()), QKeySequence::Open); 75 fileMenu->addSeparator(); 76 fileMenu->addAction("Quit", this, SLOT(close())); 77 78 QMenu* viewMenu = menuBar()->addMenu("&View"); 79 viewMenu->addAction(page()->action(QWKPage::Stop)); 80 viewMenu->addAction(page()->action(QWKPage::Reload)); 81 viewMenu->addSeparator(); 82 QAction* zoomIn = viewMenu->addAction("Zoom &In", this, SLOT(zoomIn())); 83 QAction* zoomOut = viewMenu->addAction("Zoom &Out", this, SLOT(zoomOut())); 84 QAction* resetZoom = viewMenu->addAction("Reset Zoom", this, SLOT(resetZoom())); 85 QAction* zoomText = viewMenu->addAction("Zoom Text Only", this, SLOT(toggleZoomTextOnly(bool))); 86 zoomText->setCheckable(true); 87 zoomText->setChecked(false); 88 viewMenu->addSeparator(); 89 viewMenu->addAction("Take Screen Shot...", this, SLOT(screenshot())); 90 91 zoomIn->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_Plus)); 92 zoomOut->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_Minus)); 93 resetZoom->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_0)); 94 95 QMenu* windowMenu = menuBar()->addMenu("&Window"); 96 QAction* toggleFullScreen = windowMenu->addAction("Toggle FullScreen", this, SIGNAL(enteredFullScreenMode(bool))); 97 toggleFullScreen->setShortcut(Qt::Key_F11); 98 toggleFullScreen->setCheckable(true); 99 toggleFullScreen->setChecked(false); 100 // When exit fullscreen mode by clicking on the exit area (bottom right corner) we must 101 // uncheck the Toggle FullScreen action. 102 toggleFullScreen->connect(this, SIGNAL(enteredFullScreenMode(bool)), SLOT(setChecked(bool))); 103 connect(this, SIGNAL(enteredFullScreenMode(bool)), this, SLOT(toggleFullScreenMode(bool))); 104 105 QMenu* toolsMenu = menuBar()->addMenu("&Develop"); 106 QAction* toggleFrameFlattening = toolsMenu->addAction("Toggle Frame Flattening", this, SLOT(toggleFrameFlattening(bool))); 107 toggleFrameFlattening->setCheckable(true); 108 toggleFrameFlattening->setChecked(false); 109 toolsMenu->addSeparator(); 110 toolsMenu->addAction("Change User Agent", this, SLOT(showUserAgentDialog())); 111 toolsMenu->addSeparator(); 112 toolsMenu->addAction("Load URLs from file", this, SLOT(loadURLListFromFile())); 113 114 QMenu* settingsMenu = menuBar()->addMenu("&Settings"); 115 QAction* toggleAutoLoadImages = settingsMenu->addAction("Disable Auto Load Images", this, SLOT(toggleAutoLoadImages(bool))); 116 toggleAutoLoadImages->setCheckable(true); 117 toggleAutoLoadImages->setChecked(false); 118 QAction* toggleDisableJavaScript = settingsMenu->addAction("Disable JavaScript", this, SLOT(toggleDisableJavaScript(bool))); 119 toggleDisableJavaScript->setCheckable(true); 120 toggleDisableJavaScript->setChecked(false); 121 122 m_addressBar = new QLineEdit(); 123 connect(m_addressBar, SIGNAL(returnPressed()), SLOT(changeLocation())); 124 125 QToolBar* bar = addToolBar("Navigation"); 126 bar->addAction(page()->action(QWKPage::Back)); 127 bar->addAction(page()->action(QWKPage::Forward)); 128 bar->addAction(page()->action(QWKPage::Reload)); 129 bar->addAction(page()->action(QWKPage::Stop)); 130 bar->addWidget(m_addressBar); 131 132 QShortcut* selectAddressBar = new QShortcut(Qt::CTRL | Qt::Key_L, this); 133 connect(selectAddressBar, SIGNAL(activated()), this, SLOT(openLocation())); 134 135 page()->setCreateNewPageFunction(newPageFunction); 136 137 // the zoom values are chosen to be like in Mozilla Firefox 3 138 if (!m_zoomLevels.count()) { 139 m_zoomLevels << 0.3 << 0.5 << 0.67 << 0.8 << 0.9; 140 m_zoomLevels << 1; 141 m_zoomLevels << 1.1 << 1.2 << 1.33 << 1.5 << 1.7 << 2 << 2.4 << 3; 142 } 143 144 if (m_windowOptions.startMaximized) 145 setWindowState(windowState() | Qt::WindowMaximized); 146 else 147 resize(800, 600); 148 show(); 149} 150 151void BrowserWindow::load(const QString& url) 152{ 153 m_addressBar->setText(url); 154 m_browser->load(url); 155} 156 157QWKPage* BrowserWindow::page() 158{ 159 return m_browser->view()->page(); 160} 161 162BrowserWindow* BrowserWindow::newWindow(const QString& url) 163{ 164 BrowserWindow* window; 165 if (m_windowOptions.useSeparateWebProcessPerWindow) { 166 QWKContext* context = new QWKContext(); 167 window = new BrowserWindow(context); 168 context->setParent(window); 169 } else 170 window = new BrowserWindow(m_context); 171 172 window->load(url); 173 return window; 174} 175 176void BrowserWindow::openLocation() 177{ 178 m_addressBar->selectAll(); 179 m_addressBar->setFocus(); 180} 181 182void BrowserWindow::changeLocation() 183{ 184 QString string = m_addressBar->text(); 185 m_browser->load(string); 186} 187 188void BrowserWindow::loadProgress(int progress) 189{ 190 QColor backgroundColor = QApplication::palette().color(QPalette::Base); 191 QColor progressColor = QColor(120, 180, 240); 192 QPalette pallete = m_addressBar->palette(); 193 194 if (progress <= 0 || progress >= 100) 195 pallete.setBrush(QPalette::Base, backgroundColor); 196 else { 197 QLinearGradient gradient(0, 0, width(), 0); 198 gradient.setColorAt(0, progressColor); 199 gradient.setColorAt(((double) progress) / 100, progressColor); 200 if (progress != 100) 201 gradient.setColorAt((double) progress / 100 + 0.001, backgroundColor); 202 pallete.setBrush(QPalette::Base, gradient); 203 } 204 m_addressBar->setPalette(pallete); 205} 206 207void BrowserWindow::urlChanged(const QUrl& url) 208{ 209 m_addressBar->setText(url.toString()); 210 m_browser->setFocus(); 211 m_browser->view()->setFocus(); 212} 213 214void BrowserWindow::openFile() 215{ 216#ifndef QT_NO_FILEDIALOG 217 static const QString filter("HTML Files (*.htm *.html *.xhtml);;Text Files (*.txt);;Image Files (*.gif *.jpg *.png);;SVG Files (*.svg);;All Files (*)"); 218 219 QFileDialog fileDialog(this, tr("Open"), QString(), filter); 220 fileDialog.setAcceptMode(QFileDialog::AcceptOpen); 221 fileDialog.setFileMode(QFileDialog::ExistingFile); 222 fileDialog.setOptions(QFileDialog::ReadOnly); 223 224 if (fileDialog.exec()) { 225 QString selectedFile = fileDialog.selectedFiles()[0]; 226 if (!selectedFile.isEmpty()) 227 load(selectedFile); 228 } 229#endif 230} 231 232void BrowserWindow::screenshot() 233{ 234 QPixmap pixmap = QPixmap::grabWidget(m_browser); 235 QLabel* label = 0; 236#if !defined(Q_OS_SYMBIAN) 237 label = new QLabel; 238 label->setAttribute(Qt::WA_DeleteOnClose); 239 label->setWindowTitle("Screenshot - Preview"); 240 label->setPixmap(pixmap); 241 label->show(); 242#endif 243 244#ifndef QT_NO_FILEDIALOG 245 QString fileName = QFileDialog::getSaveFileName(label, "Screenshot", QString(), QString("PNG File (.png)")); 246 if (!fileName.isEmpty()) { 247 QRegExp rx("*.png"); 248 rx.setCaseSensitivity(Qt::CaseInsensitive); 249 rx.setPatternSyntax(QRegExp::Wildcard); 250 251 if (!rx.exactMatch(fileName)) 252 fileName += ".png"; 253 254 pixmap.save(fileName, "png"); 255 if (label) 256 label->setWindowTitle(QString("Screenshot - Saved at %1").arg(fileName)); 257 } 258#endif 259} 260 261void BrowserWindow::zoomIn() 262{ 263 if (m_isZoomTextOnly) 264 m_currentZoom = page()->textZoomFactor(); 265 else 266 m_currentZoom = page()->pageZoomFactor(); 267 268 int i = m_zoomLevels.indexOf(m_currentZoom); 269 Q_ASSERT(i >= 0); 270 if (i < m_zoomLevels.count() - 1) 271 m_currentZoom = m_zoomLevels[i + 1]; 272 273 applyZoom(); 274} 275 276void BrowserWindow::zoomOut() 277{ 278 if (m_isZoomTextOnly) 279 m_currentZoom = page()->textZoomFactor(); 280 else 281 m_currentZoom = page()->pageZoomFactor(); 282 283 int i = m_zoomLevels.indexOf(m_currentZoom); 284 Q_ASSERT(i >= 0); 285 if (i > 0) 286 m_currentZoom = m_zoomLevels[i - 1]; 287 288 applyZoom(); 289} 290 291void BrowserWindow::resetZoom() 292{ 293 m_currentZoom = 1; 294 applyZoom(); 295} 296 297void BrowserWindow::toggleZoomTextOnly(bool b) 298{ 299 m_isZoomTextOnly = b; 300} 301 302void BrowserWindow::toggleFullScreenMode(bool enable) 303{ 304 bool alreadyEnabled = windowState() & Qt::WindowFullScreen; 305 if (enable ^ alreadyEnabled) 306 setWindowState(windowState() ^ Qt::WindowFullScreen); 307} 308 309void BrowserWindow::toggleFrameFlattening(bool toggle) 310{ 311 page()->preferences()->setAttribute(QWKPreferences::FrameFlatteningEnabled, toggle); 312} 313 314 315void BrowserWindow::showUserAgentDialog() 316{ 317 updateUserAgentList(); 318 319 QDialog dialog(this); 320 dialog.setWindowTitle("Change User Agent"); 321 dialog.resize(size().width() * 0.7, dialog.size().height()); 322 QVBoxLayout* layout = new QVBoxLayout(&dialog); 323 dialog.setLayout(layout); 324 325 QComboBox* combo = new QComboBox(&dialog); 326 combo->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLength); 327 combo->setEditable(true); 328 combo->insertItems(0, m_userAgentList); 329 layout->addWidget(combo); 330 331 int index = combo->findText(page()->customUserAgent()); 332 combo->setCurrentIndex(index); 333 334 QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel 335 , Qt::Horizontal, &dialog); 336 connect(buttonBox, SIGNAL(accepted()), &dialog, SLOT(accept())); 337 connect(buttonBox, SIGNAL(rejected()), &dialog, SLOT(reject())); 338 layout->addWidget(buttonBox); 339 340 if (dialog.exec() && !combo->currentText().isEmpty()) 341 page()->setCustomUserAgent(combo->currentText()); 342} 343 344void BrowserWindow::loadURLListFromFile() 345{ 346 QString selectedFile; 347#ifndef QT_NO_FILEDIALOG 348 selectedFile = QFileDialog::getOpenFileName(this, tr("Load URL list from file") 349 , QString(), tr("Text Files (*.txt);;All Files (*)")); 350#endif 351 if (selectedFile.isEmpty()) 352 return; 353 354 m_urlLoader = new UrlLoader(this, selectedFile, 0, 0); 355 m_urlLoader->loadNext(); 356} 357 358void BrowserWindow::printURL(const QUrl& url) 359{ 360 QTextStream output(stdout); 361 output << "Loaded: " << url.toString() << endl; 362} 363 364void BrowserWindow::toggleDisableJavaScript(bool enable) 365{ 366 page()->preferences()->setAttribute(QWKPreferences::JavascriptEnabled, !enable); 367} 368 369void BrowserWindow::toggleAutoLoadImages(bool enable) 370{ 371 page()->preferences()->setAttribute(QWKPreferences::AutoLoadImages, !enable); 372} 373 374void BrowserWindow::updateUserAgentList() 375{ 376 QFile file(":/useragentlist.txt"); 377 378 if (file.open(QIODevice::ReadOnly)) { 379 while (!file.atEnd()) { 380 QString agent = file.readLine().trimmed(); 381 if (!m_userAgentList.contains(agent)) 382 m_userAgentList << agent; 383 } 384 file.close(); 385 } 386 387 Q_ASSERT(!m_userAgentList.isEmpty()); 388 QWKPage* wkPage = page(); 389 if (!(wkPage->customUserAgent().isEmpty() || m_userAgentList.contains(wkPage->customUserAgent()))) 390 m_userAgentList << wkPage->customUserAgent(); 391} 392 393void BrowserWindow::applyZoom() 394{ 395 if (m_isZoomTextOnly) 396 page()->setTextZoomFactor(m_currentZoom); 397 else 398 page()->setPageZoomFactor(m_currentZoom); 399} 400 401BrowserWindow::~BrowserWindow() 402{ 403 delete m_urlLoader; 404 delete m_addressBar; 405 delete m_browser; 406} 407