blob: e3c61169602a550d50164b1547e1d63f6b09ca91 [file] [log] [blame]
/*
* Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
* Copyright (C) 2009 Girish Ramakrishnan <girish@forwardbias.in>
* Copyright (C) 2006 George Staikos <staikos@kde.org>
* Copyright (C) 2006 Dirk Mueller <mueller@kde.org>
* Copyright (C) 2006 Zack Rusin <zack@kde.org>
* Copyright (C) 2006 Simon Hausmann <hausmann@kde.org>
*
* 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 <qwebpage.h>
#include <qwebview.h>
#include <qwebframe.h>
#include <qwebsettings.h>
#include <qwebplugindatabase.h>
#include <qwebelement.h>
#include <qwebinspector.h>
#include <QtGui>
#include <QDebug>
#include <QtNetwork/QNetworkProxy>
#if QT_VERSION >= 0x040400 && !defined(QT_NO_PRINTER)
#include <QPrintPreviewDialog>
#endif
#ifndef QT_NO_UITOOLS
#include <QtUiTools/QUiLoader>
#endif
#include <QVector>
#include <QTextStream>
#include <QFile>
#include <cstdio>
#ifndef NDEBUG
void QWEBKIT_EXPORT qt_drt_garbageCollector_collect();
#endif
class WebPage : public QWebPage
{
public:
WebPage(QWidget *parent) : QWebPage(parent) {}
virtual QWebPage *createWindow(QWebPage::WebWindowType);
virtual QObject* createPlugin(const QString&, const QUrl&, const QStringList&, const QStringList&);
virtual bool supportsExtension(QWebPage::Extension extension) const
{
if (extension == QWebPage::ErrorPageExtension)
return true;
return false;
}
virtual bool extension(Extension extension, const ExtensionOption *option, ExtensionReturn *output);
};
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QString url = QString()): currentZoom(100) {
setAttribute(Qt::WA_DeleteOnClose);
if (qgetenv("QTLAUNCHER_USE_ARGB_VISUALS").toInt() == 1)
setAttribute(Qt::WA_TranslucentBackground);
QSplitter* splitter = new QSplitter(Qt::Vertical, this);
setCentralWidget(splitter);
view = new QWebView(splitter);
WebPage* page = new WebPage(view);
view->setPage(page);
connect(view, SIGNAL(loadFinished(bool)),
this, SLOT(loadFinished()));
connect(view, SIGNAL(titleChanged(const QString&)),
this, SLOT(setWindowTitle(const QString&)));
connect(view->page(), SIGNAL(linkHovered(const QString&, const QString&, const QString &)),
this, SLOT(showLinkHover(const QString&, const QString&)));
connect(view->page(), SIGNAL(windowCloseRequested()), this, SLOT(close()));
inspector = new QWebInspector(splitter);
inspector->setPage(page);
inspector->hide();
connect(this, SIGNAL(destroyed()), inspector, SLOT(deleteLater()));
connect(page, SIGNAL(webInspectorTriggered(const QWebElement&)), inspector, SLOT(show()));
setupUI();
// set the proxy to the http_proxy env variable - if present
QUrl proxyUrl = view->guessUrlFromString(qgetenv("http_proxy"));
if (proxyUrl.isValid() && !proxyUrl.host().isEmpty()) {
int proxyPort = (proxyUrl.port() > 0) ? proxyUrl.port() : 8080;
page->networkAccessManager()->setProxy(QNetworkProxy(QNetworkProxy::HttpProxy, proxyUrl.host(), proxyPort));
}
QFileInfo fi(url);
if (fi.exists() && fi.isRelative())
url = fi.absoluteFilePath();
QUrl qurl = view->guessUrlFromString(url);
if (qurl.isValid()) {
urlEdit->setText(qurl.toEncoded());
view->load(qurl);
}
// the zoom values are chosen to be like in Mozilla Firefox 3
zoomLevels << 30 << 50 << 67 << 80 << 90;
zoomLevels << 100;
zoomLevels << 110 << 120 << 133 << 150 << 170 << 200 << 240 << 300;
}
QWebPage* webPage() const {
return view->page();
}
QWebView* webView() const {
return view;
}
protected slots:
void changeLocation() {
QString string = urlEdit->text();
QUrl url = view->guessUrlFromString(string);
if (!url.isValid())
url = QUrl("http://" + string + "/");
urlEdit->setText(url.toEncoded());
view->load(url);
view->setFocus(Qt::OtherFocusReason);
}
void loadFinished() {
urlEdit->setText(view->url().toString());
QUrl::FormattingOptions opts;
opts |= QUrl::RemoveScheme;
opts |= QUrl::RemoveUserInfo;
opts |= QUrl::StripTrailingSlash;
QString s = view->url().toString(opts);
s = s.mid(2);
if (s.isEmpty())
return;
if (!urlList.contains(s))
urlList += s;
urlModel.setStringList(urlList);
}
void showLinkHover(const QString &link, const QString &toolTip) {
statusBar()->showMessage(link);
#ifndef QT_NO_TOOLTIP
if (!toolTip.isEmpty())
QToolTip::showText(QCursor::pos(), toolTip);
#endif
}
void zoomIn() {
int i = zoomLevels.indexOf(currentZoom);
Q_ASSERT(i >= 0);
if (i < zoomLevels.count() - 1)
currentZoom = zoomLevels[i + 1];
view->setZoomFactor(qreal(currentZoom)/100.0);
}
void zoomOut() {
int i = zoomLevels.indexOf(currentZoom);
Q_ASSERT(i >= 0);
if (i > 0)
currentZoom = zoomLevels[i - 1];
view->setZoomFactor(qreal(currentZoom)/100.0);
}
void resetZoom()
{
currentZoom = 100;
view->setZoomFactor(1.0);
}
void toggleZoomTextOnly(bool b)
{
view->page()->settings()->setAttribute(QWebSettings::ZoomTextOnly, b);
}
void print() {
#if QT_VERSION >= 0x040400 && !defined(QT_NO_PRINTER)
QPrintPreviewDialog dlg(this);
connect(&dlg, SIGNAL(paintRequested(QPrinter *)),
view, SLOT(print(QPrinter *)));
dlg.exec();
#endif
}
void screenshot()
{
QPixmap pixmap = QPixmap::grabWidget(view);
QLabel* label = new QLabel;
label->setAttribute(Qt::WA_DeleteOnClose);
label->setWindowTitle("Screenshot - Preview");
label->setPixmap(pixmap);
label->show();
QString fileName = QFileDialog::getSaveFileName(label, "Screenshot");
if (!fileName.isEmpty()) {
pixmap.save(fileName, "png");
label->setWindowTitle(QString("Screenshot - Saved at %1").arg(fileName));
}
}
void setEditable(bool on) {
view->page()->setContentEditable(on);
formatMenuAction->setVisible(on);
}
void dumpPlugins() {
QList<QWebPluginInfo> plugins = QWebSettings::pluginDatabase()->plugins();
foreach (const QWebPluginInfo plugin, plugins) {
qDebug() << "Plugin:" << plugin.name();
foreach (const QWebPluginInfo::MimeType mime, plugin.mimeTypes()) {
qDebug() << " " << mime.name;
}
}
}
void dumpHtml() {
qDebug() << "HTML: " << view->page()->mainFrame()->toHtml();
}
void selectElements() {
bool ok;
QString str = QInputDialog::getText(this, "Select elements", "Choose elements",
QLineEdit::Normal, "a", &ok);
if (ok && !str.isEmpty()) {
QWebElementCollection result = view->page()->mainFrame()->findAllElements(str);
foreach (QWebElement e, result)
e.setStyleProperty("background-color", "yellow");
statusBar()->showMessage(QString("%1 element(s) selected").arg(result.count()), 5000);
}
}
public slots:
void newWindow(const QString &url = QString()) {
MainWindow *mw = new MainWindow(url);
mw->show();
}
private:
QVector<int> zoomLevels;
int currentZoom;
// create the status bar, tool bar & menu
void setupUI() {
progress = new QProgressBar(this);
progress->setRange(0, 100);
progress->setMinimumSize(100, 20);
progress->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
progress->hide();
statusBar()->addPermanentWidget(progress);
connect(view, SIGNAL(loadProgress(int)), progress, SLOT(show()));
connect(view, SIGNAL(loadProgress(int)), progress, SLOT(setValue(int)));
connect(view, SIGNAL(loadFinished(bool)), progress, SLOT(hide()));
urlEdit = new QLineEdit(this);
urlEdit->setSizePolicy(QSizePolicy::Expanding, urlEdit->sizePolicy().verticalPolicy());
connect(urlEdit, SIGNAL(returnPressed()),
SLOT(changeLocation()));
QCompleter *completer = new QCompleter(this);
urlEdit->setCompleter(completer);
completer->setModel(&urlModel);
QToolBar *bar = addToolBar("Navigation");
bar->addAction(view->pageAction(QWebPage::Back));
bar->addAction(view->pageAction(QWebPage::Forward));
bar->addAction(view->pageAction(QWebPage::Reload));
bar->addAction(view->pageAction(QWebPage::Stop));
bar->addWidget(urlEdit);
QMenu *fileMenu = menuBar()->addMenu("&File");
QAction *newWindow = fileMenu->addAction("New Window", this, SLOT(newWindow()));
#if QT_VERSION >= 0x040400
fileMenu->addAction(tr("Print"), this, SLOT(print()), QKeySequence::Print);
#endif
QAction* screenshot = fileMenu->addAction("Screenshot", this, SLOT(screenshot()));
fileMenu->addAction("Close", this, SLOT(close()));
QMenu *editMenu = menuBar()->addMenu("&Edit");
editMenu->addAction(view->pageAction(QWebPage::Undo));
editMenu->addAction(view->pageAction(QWebPage::Redo));
editMenu->addSeparator();
editMenu->addAction(view->pageAction(QWebPage::Cut));
editMenu->addAction(view->pageAction(QWebPage::Copy));
editMenu->addAction(view->pageAction(QWebPage::Paste));
editMenu->addSeparator();
QAction *setEditable = editMenu->addAction("Set Editable", this, SLOT(setEditable(bool)));
setEditable->setCheckable(true);
QMenu *viewMenu = menuBar()->addMenu("&View");
viewMenu->addAction(view->pageAction(QWebPage::Stop));
viewMenu->addAction(view->pageAction(QWebPage::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 *zoomTextOnly = viewMenu->addAction("Zoom Text Only", this, SLOT(toggleZoomTextOnly(bool)));
zoomTextOnly->setCheckable(true);
zoomTextOnly->setChecked(false);
viewMenu->addSeparator();
viewMenu->addAction("Dump HTML", this, SLOT(dumpHtml()));
viewMenu->addAction("Dump plugins", this, SLOT(dumpPlugins()));
QMenu *formatMenu = new QMenu("F&ormat", this);
formatMenuAction = menuBar()->addMenu(formatMenu);
formatMenuAction->setVisible(false);
formatMenu->addAction(view->pageAction(QWebPage::ToggleBold));
formatMenu->addAction(view->pageAction(QWebPage::ToggleItalic));
formatMenu->addAction(view->pageAction(QWebPage::ToggleUnderline));
QMenu *writingMenu = formatMenu->addMenu(tr("Writing Direction"));
writingMenu->addAction(view->pageAction(QWebPage::SetTextDirectionDefault));
writingMenu->addAction(view->pageAction(QWebPage::SetTextDirectionLeftToRight));
writingMenu->addAction(view->pageAction(QWebPage::SetTextDirectionRightToLeft));
newWindow->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_N));
screenshot->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_S));
view->pageAction(QWebPage::Back)->setShortcut(QKeySequence::Back);
view->pageAction(QWebPage::Stop)->setShortcut(Qt::Key_Escape);
view->pageAction(QWebPage::Forward)->setShortcut(QKeySequence::Forward);
view->pageAction(QWebPage::Reload)->setShortcut(QKeySequence::Refresh);
view->pageAction(QWebPage::Undo)->setShortcut(QKeySequence::Undo);
view->pageAction(QWebPage::Redo)->setShortcut(QKeySequence::Redo);
view->pageAction(QWebPage::Cut)->setShortcut(QKeySequence::Cut);
view->pageAction(QWebPage::Copy)->setShortcut(QKeySequence::Copy);
view->pageAction(QWebPage::Paste)->setShortcut(QKeySequence::Paste);
zoomIn->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_Plus));
zoomOut->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_Minus));
resetZoom->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_0));
view->pageAction(QWebPage::ToggleBold)->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_B));
view->pageAction(QWebPage::ToggleItalic)->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_I));
view->pageAction(QWebPage::ToggleUnderline)->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_U));
QMenu *toolsMenu = menuBar()->addMenu("&Tools");
toolsMenu->addAction("Select elements...", this, SLOT(selectElements()));
}
QWebView *view;
QLineEdit *urlEdit;
QProgressBar *progress;
QWebInspector* inspector;
QAction *formatMenuAction;
QStringList urlList;
QStringListModel urlModel;
};
bool WebPage::extension(Extension extension, const ExtensionOption *option, ExtensionReturn *output)
{
const QWebPage::ErrorPageExtensionOption* info = static_cast<const QWebPage::ErrorPageExtensionOption*>(option);
QWebPage::ErrorPageExtensionReturn* errorPage = static_cast<QWebPage::ErrorPageExtensionReturn*>(output);
errorPage->content = QString("<html><head><title>Failed loading page</title></head><body>%1</body></html>")
.arg(info->errorString).toUtf8();
return true;
}
QWebPage *WebPage::createWindow(QWebPage::WebWindowType)
{
MainWindow *mw = new MainWindow;
mw->show();
return mw->webPage();
}
QObject *WebPage::createPlugin(const QString &classId, const QUrl &url, const QStringList &paramNames, const QStringList &paramValues)
{
Q_UNUSED(url);
Q_UNUSED(paramNames);
Q_UNUSED(paramValues);
#ifndef QT_NO_UITOOLS
QUiLoader loader;
return loader.createWidget(classId, view());
#else
Q_UNUSED(classId);
return 0;
#endif
}
class URLLoader : public QObject
{
Q_OBJECT
public:
URLLoader(QWebView* view, const QString& inputFileName)
: m_view(view)
, m_stdOut(stdout)
, m_loaded(0)
{
init(inputFileName);
}
public slots:
void loadNext()
{
QString qstr;
if (getUrl(qstr)) {
QUrl url(qstr, QUrl::StrictMode);
if (url.isValid()) {
m_stdOut << "Loading " << qstr << " ......" << ++m_loaded << endl;
m_view->load(url);
} else
loadNext();
} else
disconnect(m_view, 0, this, 0);
}
private:
void init(const QString& inputFileName)
{
QFile inputFile(inputFileName);
if (inputFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
QTextStream stream(&inputFile);
QString line;
while (true) {
line = stream.readLine();
if (line.isNull())
break;
m_urls.append(line);
}
} else {
qDebug() << "Cant't open list file";
exit(0);
}
m_index = 0;
inputFile.close();
}
bool getUrl(QString& qstr)
{
if (m_index == m_urls.size())
return false;
qstr = m_urls[m_index++];
return true;
}
private:
QVector<QString> m_urls;
int m_index;
QWebView* m_view;
QTextStream m_stdOut;
int m_loaded;
};
#include "main.moc"
int launcherMain(const QApplication& app)
{
#ifndef NDEBUG
int retVal = app.exec();
qt_drt_garbageCollector_collect();
QWebSettings::clearMemoryCaches();
return retVal;
#else
return app.exec();
#endif
}
int main(int argc, char **argv)
{
QApplication app(argc, argv);
QString url = QString("%1/%2").arg(QDir::homePath()).arg(QLatin1String("index.html"));
QWebSettings::setMaximumPagesInCache(4);
app.setApplicationName("QtLauncher");
#if QT_VERSION >= 0x040400
app.setApplicationVersion("0.1");
#endif
QWebSettings::setObjectCacheCapacities((16*1024*1024) / 8, (16*1024*1024) / 8, 16*1024*1024);
QWebSettings::globalSettings()->setAttribute(QWebSettings::PluginsEnabled, true);
QWebSettings::globalSettings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, true);
QWebSettings::enablePersistentStorage();
// To allow QWebInspector's configuration persistence
QCoreApplication::setOrganizationName("Nokia");
QCoreApplication::setApplicationName("QtLauncher");
const QStringList args = app.arguments();
if (args.contains(QLatin1String("-r"))) {
// robotized
QString listFile = args.at(2);
if (!(args.count() == 3) && QFile::exists(listFile)) {
qDebug() << "Usage: QtLauncher -r listfile";
exit(0);
}
MainWindow* window = new MainWindow;
QWebView *view = window->webView();
URLLoader loader(view, listFile);
QObject::connect(view, SIGNAL(loadFinished(bool)), &loader, SLOT(loadNext()));
loader.loadNext();
window->show();
launcherMain(app);
} else {
if (args.count() > 1)
url = args.at(1);
MainWindow* window = new MainWindow(url);
// Opens every given urls in new windows
for (int i = 2; i < args.count(); i++)
window->newWindow(args.at(i));
window->show();
launcherMain(app);
}
}