Home | History | Annotate | Download | only in qt
      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 
     34 static QWKPage* newPageFunction(QWKPage* page)
     35 {
     36     BrowserWindow* window = new BrowserWindow(page->context());
     37     return window->page();
     38 }
     39 
     40 QVector<qreal> BrowserWindow::m_zoomLevels;
     41 
     42 BrowserWindow::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 
    151 void BrowserWindow::load(const QString& url)
    152 {
    153     m_addressBar->setText(url);
    154     m_browser->load(url);
    155 }
    156 
    157 QWKPage* BrowserWindow::page()
    158 {
    159     return m_browser->view()->page();
    160 }
    161 
    162 BrowserWindow* 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 
    176 void BrowserWindow::openLocation()
    177 {
    178     m_addressBar->selectAll();
    179     m_addressBar->setFocus();
    180 }
    181 
    182 void BrowserWindow::changeLocation()
    183 {
    184     QString string = m_addressBar->text();
    185     m_browser->load(string);
    186 }
    187 
    188 void 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 
    207 void BrowserWindow::urlChanged(const QUrl& url)
    208 {
    209     m_addressBar->setText(url.toString());
    210     m_browser->setFocus();
    211     m_browser->view()->setFocus();
    212 }
    213 
    214 void 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 
    232 void 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 
    261 void 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 
    276 void 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 
    291 void BrowserWindow::resetZoom()
    292 {
    293     m_currentZoom = 1;
    294     applyZoom();
    295 }
    296 
    297 void BrowserWindow::toggleZoomTextOnly(bool b)
    298 {
    299     m_isZoomTextOnly = b;
    300 }
    301 
    302 void BrowserWindow::toggleFullScreenMode(bool enable)
    303 {
    304     bool alreadyEnabled = windowState() & Qt::WindowFullScreen;
    305     if (enable ^ alreadyEnabled)
    306         setWindowState(windowState() ^ Qt::WindowFullScreen);
    307 }
    308 
    309 void BrowserWindow::toggleFrameFlattening(bool toggle)
    310 {
    311     page()->preferences()->setAttribute(QWKPreferences::FrameFlatteningEnabled, toggle);
    312 }
    313 
    314 
    315 void 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 
    344 void 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 
    358 void BrowserWindow::printURL(const QUrl& url)
    359 {
    360     QTextStream output(stdout);
    361     output << "Loaded: " << url.toString() << endl;
    362 }
    363 
    364 void BrowserWindow::toggleDisableJavaScript(bool enable)
    365 {
    366     page()->preferences()->setAttribute(QWKPreferences::JavascriptEnabled, !enable);
    367 }
    368 
    369 void BrowserWindow::toggleAutoLoadImages(bool enable)
    370 {
    371     page()->preferences()->setAttribute(QWKPreferences::AutoLoadImages, !enable);
    372 }
    373 
    374 void 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 
    393 void BrowserWindow::applyZoom()
    394 {
    395     if (m_isZoomTextOnly)
    396         page()->setTextZoomFactor(m_currentZoom);
    397     else
    398         page()->setPageZoomFactor(m_currentZoom);
    399 }
    400 
    401 BrowserWindow::~BrowserWindow()
    402 {
    403     delete m_urlLoader;
    404     delete m_addressBar;
    405     delete m_browser;
    406 }
    407