/** This file is part of WebScraps ** * * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).* * All rights reserved. * Contact: Nokia Corporation (qt-info@nokia.com)** * You may use this file under the terms of the BSD license as follows: * 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. * 3. Neither the name of Nokia Corporation and its Subsidiary(-ies) nor the names of * its contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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 #include #include #include #include #include #include #include #include #include #include #include #include "mainwindow.h" #include "ui_mainwindow.h" #include "webview.h" #include "webscrap.h" #include "searchlineedit.h" MainWindow::MainWindow(QWidget *parent) : GraphicsView(parent) , m_settings(new QSettings("Nokia", "WebScraps", this)) { setScene(new QGraphicsScene); setMouseTracking(true); QLinearGradient bgGradient; bgGradient.setStart(0, 0); bgGradient.setFinalStop(0, 800); bgGradient.setColorAt(0, QColor("#80c342")); bgGradient.setColorAt(1, Qt::white); setBackgroundBrush(bgGradient); // web settings QWebSettings::globalSettings()->setAttribute(QWebSettings::JavascriptEnabled, true); QWebSettings::globalSettings()->setAttribute(QWebSettings::PluginsEnabled, true); QWebSettings::globalSettings()->setAttribute(QWebSettings::JavascriptCanOpenWindows, false); QWebSettings::globalSettings()->setAttribute(QWebSettings::JavascriptCanAccessClipboard, true); initBrowser(); // create the browser createBrowserToolbar(scene()); connect(m_webView->page(), SIGNAL(loadProgress(int)), m_addressBar, SLOT(setProgress(int))); createAnimations(); createScrapsToolbar(scene()); loadSettings(); // load the saved scraps and add them to the animations // make the toolbars of the same size const QSizeF toolBarSize = m_browserToolbar->effectiveSizeHint(Qt::PreferredSize).expandedTo(m_scrapsToolbar->effectiveSizeHint(Qt::PreferredSize)); m_scrapsToolbar->resize(toolBarSize); m_browserToolbar->resize(toolBarSize); // init states QState *seeScraps = new QState; QState *browseWeb = new QState; m_stateMachine.addState(seeScraps); m_stateMachine.addState(browseWeb); m_stateMachine.setInitialState(seeScraps); // define transitions QSignalTransition *transitionToBrowser = seeScraps->addTransition(m_gotoBrowserButton, SIGNAL(clicked()), browseWeb); QSignalTransition *transitionToScraps = browseWeb->addTransition(m_gotoScrapsButton, SIGNAL(clicked()), seeScraps); QSignalTransition *transitionToScraps2 = browseWeb->addTransition(m_webView, SIGNAL(scrapAdded(QUrl, QSize, QRect, QPoint)), seeScraps); // associate animations and actions transitionToBrowser->addAnimation(m_scrapsToBrowserAnimation); transitionToScraps->addAnimation(m_browserToScrapsAnimation); transitionToScraps2->addAnimation(m_browserToScrapsAnimation); connect(browseWeb, SIGNAL(entered()), SLOT(disableScrapSelection())); connect(browseWeb, SIGNAL(entered()), m_webView, SLOT(enableCachedMode())); connect(m_browserToScrapsAnimation, SIGNAL(finished()), m_webView, SLOT(disableCachedMode())); connect(browseWeb, SIGNAL(entered()), SLOT(showBrowserToolbar())); connect(seeScraps, SIGNAL(entered()), SLOT(showScrapsToolbar())); seeScraps->assignProperty(this, "webTitleShown", false); browseWeb->assignProperty(this, "webTitleShown", true); connect(seeScraps, SIGNAL(propertiesAssigned()), SLOT(adjustTitle())); connect(browseWeb, SIGNAL(propertiesAssigned()), SLOT(adjustTitle())); m_stateMachine.start(); } void MainWindow::addScrap(const QUrl &url, const QSize &pageSize, const QRect &scrapRect, const QPoint &position, qreal xScale, qreal yScale, int refreshIntervalMins) { WebScrap *webscrap = new WebScrap(url, pageSize, scrapRect); webscrap->setRefreshInterval(refreshIntervalMins * 60 * 1000); // milliseconds WebScrapContainer *container = new WebScrapContainer(webscrap, scene(), xScale, yScale); container->setPos(position - webscrap->pos()); connect(container, SIGNAL(frameClicked()), SLOT(bubbleUpScrap())); connect(container, SIGNAL(removeSelf()), SLOT(removeSenderScrap())); m_dropDownList->addItem(QWebSettings::iconForUrl(url), url.toString(), qVariantFromValue(container)); connect(webscrap, SIGNAL(loadFinished(bool)), SLOT(updateDropDownList())); m_scraps << container; container->setZValue(m_scraps.count()); bubbleUpScrap(container); addScrapToAnimations(container); } void MainWindow::initBrowser() { m_webView = new WebView(scene()); m_webView->setPos(sceneRect().topLeft()); m_webView->setOpacity(0); m_webView->setZValue(-1); setCentralWidget(m_webView); m_webView->load(QUrl("http://qt.nokia.com/")); connect(m_webView, SIGNAL(loadFinished(bool)), SLOT(adjustLocation())); connect(m_webView, SIGNAL(titleChanged(const QString&)), SLOT(adjustTitle())); connect(m_webView, SIGNAL(scrapAdded(QUrl, QSize, QRect, QPoint)), SLOT(addScrap(QUrl, QSize, QRect, QPoint))); } void MainWindow::createScrapsToolbar(QGraphicsScene *scene) { m_scrapsToolbar = new GraphicsToolBar(scene); m_scrapsToolbar->hide(); m_dropDownList = new QComboBox; m_dropDownList->setMinimumContentsLength(18); m_dropDownList->addItem(tr("Locate"), 0); m_searchBar = new SearchLineEdit; m_searchBar->setText(QString()); m_gotoBrowserButton = new QToolButton; m_gotoBrowserButton->setIcon(QIcon(":/icons/internet.png")); m_gotoBrowserButton->setText(tr("Go to browser")); m_gotoBrowserButton->setToolTip(tr("Go to browser")); m_scrapsToolbar->addWidget(m_dropDownList); m_scrapsToolbar->addWidget(m_searchBar); m_scrapsToolbar->addWidget(m_gotoBrowserButton); m_scrapsToolbar->setPos(325, 5); m_scrapsToolbar->setZValue(10000); m_scrapsToolbar->setBackgroundBrush(palette().background()); connect(m_dropDownList, SIGNAL(activated(int)), SLOT(scrapDropDownListActivated(int))); connect(m_searchBar, SIGNAL(textChanged(QString)), SLOT(searchTextChanged(QString))); } void MainWindow::createBrowserToolbar(QGraphicsScene *scene) { m_browserToolbar = new GraphicsToolBar(scene); m_browserToolbar->hide(); m_addressBar = new AddressBar; m_selectScrapsButton = new QToolButton; m_selectScrapsButton->setIcon(QIcon(":/icons/cutscrap.png")); m_selectScrapsButton->setText(tr("Add a scrap")); m_selectScrapsButton->setToolTip(tr("Create a scrap from current page")); m_selectScrapsButton->setCheckable(true); m_gotoScrapsButton = new QToolButton; m_gotoScrapsButton->setIcon(QIcon(":/icons/scraps.png")); m_gotoScrapsButton->setText(tr("View scraps")); m_gotoScrapsButton->setToolTip(tr("View existing scraps")); QToolButton *backBtn = new QToolButton; QToolButton *forwardBtn = new QToolButton; QToolButton *reloadBtn = new QToolButton; QToolButton *stopBtn = new QToolButton; backBtn->setDefaultAction(m_webView->page()->action(QWebPage::Back)); forwardBtn->setDefaultAction(m_webView->page()->action(QWebPage::Forward)); reloadBtn->setDefaultAction(m_webView->page()->action(QWebPage::Reload)); stopBtn->setDefaultAction(m_webView->page()->action(QWebPage::Stop)); m_browserToolbar->addWidget(backBtn); m_browserToolbar->addWidget(forwardBtn); m_browserToolbar->addWidget(reloadBtn); m_browserToolbar->addWidget(stopBtn); m_browserToolbar->addWidget(m_selectScrapsButton); m_browserToolbar->addWidget(m_addressBar); m_browserToolbar->addWidget(m_gotoScrapsButton); m_addressBar->setMinimumWidth(200); m_browserToolbar->setPos(325, 5); m_browserToolbar->setZValue(10000); m_browserToolbar->setBackgroundBrush(palette().background()); connect(m_selectScrapsButton, SIGNAL(toggled(bool)), m_webView, SLOT(setScrapSelectionEnabled(bool))); connect(m_addressBar, SIGNAL(returnPressed()), SLOT(changeLocation())); } MainWindow::~MainWindow() { saveSettings(); } void MainWindow::changeLocation() { QUrl url = QUrl::fromUserInput(m_addressBar->text()); m_webView->load(url); m_webView->setFocus(); } void MainWindow::adjustLocation() { m_addressBar->setText(m_webView->url().toString()); } void MainWindow::adjustTitle() { QString title("WebScraps - "); if (m_isWebTitleShown) title += m_webView->title(); else title += QString("%1 scraps").arg(m_scraps.count()); setWindowTitle(title); } void MainWindow::createAnimations() { m_scrapsEnter = new QParallelAnimationGroup(this); // scraps will be added to this later m_scrapsLeave = new QParallelAnimationGroup(this); // scraps will be added to this later m_scrapsFlyOffset = QApplication::desktop()->screenGeometry().bottomRight() - QApplication::desktop()->screenGeometry().topLeft(); QAbstractAnimation *browserEnter = createBrowserAnim(Enter, this); QAbstractAnimation *browserLeave = createBrowserAnim(Leave, this); m_browserToScrapsAnimation = new QParallelAnimationGroup(this); m_browserToScrapsAnimation->addAnimation(browserLeave); m_browserToScrapsAnimation->addAnimation(m_scrapsEnter); m_scrapsToBrowserAnimation = new QParallelAnimationGroup(this); m_scrapsToBrowserAnimation->addAnimation(m_scrapsLeave); m_scrapsToBrowserAnimation->addAnimation(browserEnter); } void MainWindow::addScrapToAnimations(WebScrapContainer *container) { Q_ASSERT(m_scrapsEnter); Q_ASSERT(m_scrapsLeave); QPropertyAnimation *enterAnim = new QPropertyAnimation(container, "pos", this); enterAnim->setDuration(250 + 150 * m_scraps.count()); enterAnim->setEndValue(container->pos()); enterAnim->setEasingCurve(QEasingCurve::OutCubic); m_scrapsEnter->addAnimation(enterAnim); QPropertyAnimation *leaveAnim = new QPropertyAnimation(container, "pos", this); leaveAnim->setDuration(250 + 150 * m_scraps.count()); leaveAnim->setEndValue(sceneRect().center() + m_scrapsFlyOffset); leaveAnim->setEasingCurve(QEasingCurve::InCubic); m_scrapsLeave->addAnimation(leaveAnim); container->setEnterAnimation(enterAnim); container->setLeaveAnimation(leaveAnim); } void MainWindow::removeScrapFromAnimations(WebScrapContainer *container) { QPropertyAnimation *enterAnim = container->enterAnimation(); m_scrapsEnter->removeAnimation(enterAnim); enterAnim->deleteLater(); QPropertyAnimation *leaveAnim = container->leaveAnimation(); m_scrapsLeave->removeAnimation(leaveAnim); leaveAnim->deleteLater(); } QAbstractAnimation* MainWindow::createBrowserAnim(const Movement move, QObject *parent) { QPropertyAnimation *anim = new QPropertyAnimation(m_webView, "opacity", parent); anim->setDuration(250); if (move == Enter) { anim->setStartValue(0.0); anim->setEndValue(1.0); } if (move == Leave) { anim->setStartValue(1.0); anim->setEndValue(0.0); } return anim; } QAbstractAnimation* MainWindow::createToolbarAnim(GraphicsToolBar *fromToolbar, GraphicsToolBar *toToolbar, RotateDirection direction, QObject *parent) { QSequentialAnimationGroup *seqAnim = new QSequentialAnimationGroup(parent); QPropertyAnimation *rotateAnim1 = new QPropertyAnimation(fromToolbar->rotation(), "angle", seqAnim); fromToolbar->rotation()->setOrigin(QVector3D(fromToolbar->rect().center())); rotateAnim1->setDuration(250); rotateAnim1->setStartValue(0.0); if (direction == Clockwise) rotateAnim1->setEndValue(80.0); else rotateAnim1->setEndValue(-80.0); QPointF delta = fromToolbar->rect().center() - toToolbar->rect().center(); toToolbar->setPos(fromToolbar->pos()); toToolbar->moveBy(delta.x(), delta.y()); connect(rotateAnim1, SIGNAL(finished()), fromToolbar, SLOT(hide())); connect(rotateAnim1, SIGNAL(finished()), toToolbar, SLOT(show())); QPropertyAnimation *rotateAnim2 = new QPropertyAnimation(toToolbar->rotation(), "angle", seqAnim); toToolbar->rotation()->setOrigin(QVector3D(toToolbar->rect().center())); rotateAnim2->setDuration(250); if (direction == Clockwise) rotateAnim2->setStartValue(-80.0); else rotateAnim2->setStartValue(80.0); rotateAnim2->setEndValue(0.0); seqAnim->addAnimation(rotateAnim1); seqAnim->addAnimation(rotateAnim2); return seqAnim; } void MainWindow::bubbleUpScrap(QGraphicsWidget *scrap) { if (!scrap && sender()) scrap = qobject_cast(sender()); if (scrap) { foreach(QGraphicsWidget *s, m_scraps) { if (s == scrap && s->zValue() < 1000) s->setZValue(s->zValue() + 1000); if (s != scrap && s->zValue() > 1000) s->setZValue(s->zValue() - 1000); } } } void MainWindow::bubbleUpScraps(QList scraps) { if (!scraps.isEmpty()) { foreach(QGraphicsWidget *s, m_scraps) { if (scraps.contains(s) && s->zValue() < 1000) s->setZValue(s->zValue() + 1000); if (!scraps.contains(s) && s->zValue() > 1000) s->setZValue(s->zValue() - 1000); } } } void MainWindow::removeSenderScrap() { WebScrapContainer *scrap = 0; if (sender()) scrap = qobject_cast(sender()); if (scrap) { scene()->removeItem(scrap); for (int i = 0; i < m_scraps.count(); i++) { if (m_scraps.at(i) == scrap) { m_scraps.removeAt(i); m_dropDownList->removeItem(i + 1); } } scrap->deleteLater(); removeScrapFromAnimations(scrap); } adjustTitle(); } void MainWindow::updateDropDownList() { WebScrap *scrap = 0; if (sender()) scrap = qobject_cast(sender()); if (scrap) { for (int i = 0; i < m_dropDownList->count(); i++) { WebScrapContainer *container = m_dropDownList->itemData(i).value(); if (container && container->webScrap() == scrap) { m_dropDownList->setItemText(i, scrap->title()); m_dropDownList->setItemIcon(i, scrap->page()->mainFrame()->icon()); } } } } void MainWindow::scrapDropDownListActivated(int index) { WebScrapContainer *scrap = m_dropDownList->itemData(index).value(); for (int i = 0; i < m_scraps.count(); i++) { WebScrapContainer *ithScrap = qobject_cast(m_scraps.at(i)); ithScrap->setLocated(ithScrap == scrap); } bubbleUpScrap(scrap); } void MainWindow::searchTextChanged(const QString& text) { QList matchingScraps; for (int i = 0; i < m_scraps.count(); i++) { WebScrapContainer *ithScrap = qobject_cast(m_scraps.at(i)); bool isHighlighted = ithScrap->webScrap()->highlightText(text); ithScrap->setSearchMatched(isHighlighted); if (isHighlighted) matchingScraps << ithScrap; } bubbleUpScraps(matchingScraps); } void MainWindow::saveSettings() { m_settings->setValue("mainwindow/size", size()); m_settings->setValue("mainwindow/pos", pos()); m_settings->setValue("browser/url", m_webView->url().toString()); m_settings->setValue("browser/toolbarpos", m_browserToolbar->pos().toPoint()); m_settings->setValue("scraps/toolbarpos", m_scrapsToolbar->pos().toPoint()); m_settings->beginWriteArray("scraps", m_scraps.count()); for (int i = 0; i < m_scraps.count(); i++) { m_settings->setArrayIndex(i); WebScrapContainer *container = qobject_cast(m_scraps.at(i)); WebScrap *scrap = 0; if (container) scrap = container->webScrap(); if (scrap) { m_settings->setValue("url", scrap->url().toString()); m_settings->setValue("pageSize", scrap->page()->viewportSize()); m_settings->setValue("topLeft", scrap->scrapRect().topLeft()); m_settings->setValue("size", scrap->scrapRect().size()); QPointF containerPos = container->enterAnimation()->endValue().toPointF(); m_settings->setValue("pos", (containerPos + scrap->pos()).toPoint()); m_settings->setValue("xScale", container->scrapScale()->xScale()); m_settings->setValue("yScale", container->scrapScale()->yScale()); m_settings->setValue("refresh_m", int(scrap->refreshInterval() / 60000)); } } m_settings->endArray(); } void MainWindow::loadSettings() { if (m_settings->contains("mainwindow/size")) resize(m_settings->value("mainwindow/size", size()).toSize()); if (m_settings->contains("mainwindow/pos")) move(m_settings->value("mainwindow/pos", pos()).toPoint()); m_webView->setUrl(QUrl(m_settings->value("browser/url", "http://qt.nokia.com/").toString())); int count = m_settings->beginReadArray("scraps"); if (count) { for (int i = 0; i < count; i++) { m_settings->setArrayIndex(i); QString url = m_settings->value("url").toString(); QRect scrapRect; scrapRect.setTopLeft(m_settings->value("topLeft").toPoint()); scrapRect.setSize(m_settings->value("size").toSize()); QSize pageSize = m_settings->value("pageSize", QSize(800, 600)).toSize(); QPoint pos = m_settings->value("pos").toPoint(); qreal xScale = m_settings->value("xScale", 1.0).toReal(); qreal yScale = m_settings->value("yScale", 1.0).toReal(); int refreshMins = m_settings->value("refresh_m", 60).toInt(); addScrap(url, pageSize, scrapRect, pos, xScale, yScale, refreshMins); } } else { addScrap(QUrl("http://www.gocomics.com/calvinandhobbes/"), QSize(600, 201), QRect(30, 299, 600, 201), QPoint(17, 37)); addScrap(QUrl("http://dilbert.com/"), QSize(640, 199), QRect(20, 197, 640, 199), QPoint(14, 285)); addScrap(QUrl("http://www.cnn.com/"), QSize(248, 281), QRect(9, 508, 248, 281), QPoint(677, 39)); addScrap(QUrl("http://www.techcrunch.com/"), QSize(667, 257), QRect(5, 174, 667, 257), QPoint(543, 363), 0.6, 0.6); resize(950, 540); } m_settings->endArray(); } void MainWindow::setWebTitleShown(bool shown) { m_isWebTitleShown = shown; } bool MainWindow::webTitleShown() const { return m_isWebTitleShown; } void MainWindow::showBrowserToolbar() { QAbstractAnimation *anim = createToolbarAnim(m_scrapsToolbar, m_browserToolbar, AntiClockwise, this); anim->start(QAbstractAnimation::DeleteWhenStopped); } void MainWindow::showScrapsToolbar() { QAbstractAnimation *anim = createToolbarAnim(m_browserToolbar, m_scrapsToolbar, Clockwise, this); anim->start(QAbstractAnimation::DeleteWhenStopped); } void MainWindow::disableScrapSelection() { if (m_selectScrapsButton) m_selectScrapsButton->setChecked(false); }