browsercore/appfw/Api/Views/HistoryView.cpp
author hgs
Tue, 29 Jun 2010 00:46:29 -0400
changeset 3 0954f5dd2cd0
parent 0 1450b09d0cfd
child 16 3c88a81ff781
permissions -rw-r--r--
201026

/*
* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 2.1 of the License.
* 
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program.  If not, 
* see "http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html/".
*
* Description:
*
*/


#include "webpagecontroller.h"
#include "FlowInterface.h"
#include "HistoryView_p.h"
#include "HistoryView.h"
#include "HistoryViewEventContext.h"

#include <QWebHistory>
#include <QWebFrame>
#include "wrtbrowsercontainer.h"
#include "webpagedata.h"
#include "scriptobjects.h"

#include <QDebug>

namespace WRT {

HistoryViewPrivate::HistoryViewPrivate(WebPageController * pageMgr,
                                       QWidget* parent) :
    m_flowInterface(0),
    m_widgetParent(parent),
    m_graphicsWidgetParent(0),
    m_pageManager(pageMgr),
    m_activePage(0),
    m_historyIndex(0),
    m_isActive(false)
{
    Q_ASSERT(m_pageManager);
    init();
}

HistoryViewPrivate::HistoryViewPrivate(WebPageController * pageMgr,
                                       QGraphicsWidget* parent) :
    m_flowInterface(0),
    m_widgetParent(0),
    m_graphicsWidgetParent(parent),
    m_pageManager(pageMgr),
    m_activePage(0),
    m_historyIndex(0),
    m_isActive(false)
{
    Q_ASSERT(m_pageManager);
    init();
}

HistoryViewPrivate::~HistoryViewPrivate()
{
    delete m_actionForward;
    delete m_actionBack;
    delete m_actionOK;
    delete m_actionCancel;
}

void HistoryViewPrivate::init()
{
    // create the view's actions
    m_actionForward = new QAction("Forward",m_widgetParent);
    m_actionForward->setObjectName("Forward");
    m_actionBack = new QAction("Back",m_widgetParent);
    m_actionBack->setObjectName("Back");
    m_actionOK = new QAction("OK",m_widgetParent);
    m_actionOK->setObjectName("OK");
    m_actionCancel = new QAction("Cancel",m_widgetParent);
    m_actionCancel->setObjectName("Cancel");
}

/*!
 * \class HistoryView
 *
 * \brief The base class for the HistoryViews
 *
 * This class provides the basic routines to enable history navigation.
 * Derived classes (such as HistoryFlowView, and HistoryLiteView) supply
 * the exact "FlowInterface" to be used, and rely on much of the base-class functionality
 * for signal/slots, extracting history items from the current page, etc.
 */

/*!
  Basic HistoryView constructor requires a PageManager to manage the pages
  and a parent QWidget
*/
HistoryView::HistoryView(WebPageController * pageMgr,
                         QWidget* parent) :
    d(new HistoryViewPrivate(pageMgr, parent))
{
}

/*!
  Basic HistoryView constructor requires a PageManager to manage the pages
  and a parent QGraphicsWidget
*/
HistoryView::HistoryView(WebPageController * pageMgr,
                         QGraphicsWidget* parent) :
    d(new HistoryViewPrivate(pageMgr, parent))
{
}


HistoryView::~HistoryView()
{
    delete d;
}

/*!
  Retrieve the WebPageController assigned to this view
*/
WebPageController* HistoryView::webPageController()
{
    return d->m_pageManager;
}

/*!
  Return the view's Forward QAction
  For scrolling the history view forwards
*/
QAction * HistoryView::getActionForward()
{
    return d->m_actionForward;
}

/*!
  Return the view's Back QAction
  For scrolling the history view backwards
*/
QAction * HistoryView::getActionBack()
{
    return d->m_actionBack;
}

/*!
  Return the view's OK QAction
  For invoking the view's OK
*/
QAction * HistoryView::getActionOK()
{
    return d->m_actionOK;
}

/*!
  Return the view's Cancel QAction
  For invoking the view's Cancel
*/
QAction * HistoryView::getActionCancel()
{
    return d->m_actionCancel;
}

/*!
  Return the widget handle of this view
*/
QGraphicsWidget* HistoryView::widget() const
{
    return d->m_flowInterface;
}

/*!
  Return the title of this view for display
*/
QString HistoryView::title() const
{
    return QString("History");
}

/*!
  Return whether this view is active or not
*/
bool HistoryView::isActive()
{
    return d->m_isActive;
}


/*!
  Return the list of public QActions most relevant to the view's current context
  (most approptiate for contextual menus, etc.
*/
QList<QAction*> HistoryView::getContext()
{
    // for now, all actions valid at all times
    // but there may be some logic here to determine context
    QList<QAction*> contextList;
    contextList <<
        d->m_actionForward <<
        d->m_actionBack <<
        d->m_actionOK <<
        d->m_actionCancel;
    return contextList;
}



/*!
  activate the view's resources. Could be connected by client to view visibility
*/
void HistoryView::activate()
{
    Q_ASSERT(!d->m_isActive);

    if(!d->m_flowInterface)
        return;

    d->m_flowInterface->init();
    updateHistory(true);
    
    // now forward visual flow lite's signals
    connect(d->m_flowInterface, SIGNAL(centerIndexChanged(int)), SIGNAL(centerIndexChanged(int)));
    connect(d->m_flowInterface, SIGNAL(ok(int)), this, SIGNAL(ok(int)));
    connect(d->m_flowInterface, SIGNAL(cancel()), this, SIGNAL(cancel()));

    // internally process the index change signal as well, and page load complete
    connect(d->m_flowInterface, SIGNAL(centerIndexChanged(int)), this, SLOT(updateActions(int)));
    connect(d->m_pageManager,SIGNAL(loadFinished(bool)),this,SLOT(updateHistory(bool)));

    // auto-link relevant actions to slots
    connect(d->m_actionForward, SIGNAL(triggered()), this, SLOT(forward()));
    connect(d->m_actionBack, SIGNAL(triggered()), this, SLOT(back()));

    widget()->installEventFilter(this);
    connect(this, SIGNAL(contextEvent(QObject *)), jsObject(), SLOT(onContextEvent(QObject *)));

    // show and set index
    d->m_flowInterface->show();
    d->m_historyIndex = 0;
    d->m_isActive = true;
    
    emit activated();
}

/*!
  deactivate the view's resources. Could be connected by client to view visibility
*/
void HistoryView::deactivate()
{
    Q_ASSERT(d->m_isActive);

    if(!d->m_flowInterface)
        return;

    // disconnect signals
    disconnect(d->m_flowInterface, SIGNAL(centerIndexChanged(int)), this, SIGNAL(centerIndexChanged(int)));
    disconnect(d->m_flowInterface, SIGNAL(ok(int)), this, SIGNAL(ok(int)));
    disconnect(d->m_flowInterface, SIGNAL(cancel()), this, SIGNAL(cancel()));

    // internally process the index change signal as well
    disconnect(d->m_flowInterface, SIGNAL(centerIndexChanged(int)), this, SLOT(updateActions(int)));
    disconnect(d->m_pageManager,SIGNAL(loadFinished(bool)),this,SLOT(updateHistory(bool)));

    // auto-link relevant actions to slots
    disconnect(d->m_actionForward, SIGNAL(triggered()), this, SLOT(forward()));
    disconnect(d->m_actionBack, SIGNAL(triggered()), this, SLOT(back()));

    widget()->removeEventFilter(this);
    disconnect(this, SIGNAL(contextEvent(QObject *)), jsObject(), SLOT(onContextEvent(QObject *)));
    
    // cleanup
    d->m_flowInterface->deleteLater();
    d->m_flowInterface = NULL;
    d->m_isActive = false;
    
    emit deactivated();
}

void HistoryView::updateHistory(bool status)
{
    if (!status) {
        return;
    }

    if (!d->m_flowInterface) {
        return;
    }

    // clear PictureFlow
    d->m_flowInterface->clear();

    d->m_activePage = d->m_pageManager->currentPage();

    if (d->m_activePage->history()->count() < 0) {
        return;
    }

    QWebHistoryItem item = d->m_activePage->history()->currentItem();
    d->m_activePage->savePageDataToHistoryItem(d->m_activePage->mainFrame(), &item);

    QList<QWebHistoryItem> items = d->m_activePage->history()->items();
    for (int i = 0; i < d->m_activePage->history()->count(); i++) {
        QWebHistoryItem item = items.at(i);
        WebPageData data = item.userData().value<WebPageData>();
        QImage img = data.m_thumbnail;
        d->m_flowInterface->addSlide(img);
    }

    int currentItemIndex(d->m_activePage->history()->currentItemIndex());
    d->m_flowInterface->setCenterIndex(currentItemIndex);
    updateActions(currentItemIndex);
}

int HistoryView::currentIndex() {

    return (d->m_activePage->history()->currentItemIndex());
}

/*!
  set the history view's center index
*/
void HistoryView::setCenterIndex(int index)
{
    // first emit center index change
    emit centerIndexChanged(index);

    d->m_historyIndex = index - d->m_activePage->history()->currentItemIndex();

    emit titleChanged(itemTitle(d->m_historyIndex));

    //if(d->m_flowInterface)
    //{
    //   qDebug() << "Setting center index " << index;
        //d->m_flowInterface->setCurentIndex(index);
    //}

}

/*!
  scroll forward in the history view
*/
void HistoryView::forward()
{
    if(!d->m_flowInterface)
        return;

    d->m_flowInterface->showNext();
}

/*!
  scroll back in the history view
*/
void HistoryView::back()
{
    if(!d->m_flowInterface)
        return;

    d->m_flowInterface->showPrevious();
}

void HistoryView::updateActions(int centerIndex)
{
    d->m_actionBack->setEnabled(centerIndex != 0);
    d->m_actionForward->setEnabled(centerIndex < (d->m_activePage->history()->count() - 1));
}

QRect HistoryView::centralRect()
{
    if(!d->m_flowInterface)
        return QRect();

    return d->m_flowInterface->centralRect();
}

bool HistoryView::eventFilter(QObject *obj, QEvent *event)
{
    if (event->type() == QEvent::ContextMenu && obj == widget()) {
        return handleWidgetContextMenuEvent(static_cast<QContextMenuEvent *>(event));
    }

    // standard event processing
    return ControllableViewBase::eventFilter(obj, event);
}

bool HistoryView::handleWidgetContextMenuEvent(QContextMenuEvent *event)
{
//        WRT::HistoryViewEventContext *context = 
//            new WRT::HistoryViewEventContext(type(), 
//                                             cmEvent->pos(), 
//                                             d->m_flowInterface->centerIndex(), 
//                                             itemTitle(d->m_flowInterface->centerIndex()));

    // Create a javascript-accessible object with properties containing the required info.
    QObject *context = new QObject();
    context->setObjectName("historyContextEvent");
    context->setProperty("viewType", type());
    context->setProperty("itemIndex", d->m_flowInterface->centerIndex());
    context->setProperty("itemTitle", itemTitle(d->m_flowInterface->centerIndex()));

    // Create an object representing the position of the event.  Make it a child of the context object
    // so it can be accessed from javascript.
    new ScriptPoint(context, event->pos(), "pos");
    
    // Pass ownership to the javascript engine.
    QWebFrame *chrome = chromeFrame();
    if(chrome) {
        chrome->addToJavaScriptWindowObject(context->objectName(), context, QScriptEngine::ScriptOwnership);
    }

    emit contextEvent(context);
            
    return true;
}

QString HistoryView::itemTitle(int index) const
{
    QWebHistoryItem item = d->m_activePage->history()->itemAt(d->m_flowInterface->centerIndex());
    QString title;
    if (item.isValid()) {
        title = item.title();
        if (title.isNull() || title.isEmpty()) {
            title = item.url().toString();
        }
    }
    return title;
}

// -------------------------------------------

HistoryViewJSObject::HistoryViewJSObject(HistoryView* view, QWebFrame* webFrame, const QString& objectName)
  : ControllableViewJSObject(view, webFrame, objectName)
{
    connect(view,SIGNAL(ok(int)),this,SLOT(ok(int)));
    connect(view,SIGNAL(cancel()),this,SLOT(cancel()));
    
    connect(view,SIGNAL(activated()),this,SIGNAL(activated()));
    connect(view,SIGNAL(deactivated()),this,SIGNAL(deactivated()));
}

HistoryViewJSObject::~HistoryViewJSObject()
{
    disconnect(static_cast<HistoryView*>(m_contentView),SIGNAL(ok(int)),this,SLOT(ok(int)));
    disconnect(static_cast<HistoryView*>(m_contentView),SIGNAL(cancel()),this,SLOT(cancel()));
    
    disconnect(static_cast<HistoryView*>(m_contentView),SIGNAL(activated()),this,SIGNAL(activated()));
    disconnect(static_cast<HistoryView*>(m_contentView),SIGNAL(deactivated()),this,SIGNAL(deactivated()));
}

void HistoryViewJSObject::ok(int item)
{
    emit done(item);
}

void HistoryViewJSObject::cancel()
{
    emit done(historyView()->currentIndex());
}

void HistoryViewJSObject::onContextEvent(QObject *context){
    emit contextEvent(context);
}

/*!
  \fn void HistoryView::centerIndexChanged(int index);
  emitted when the center index changed
*/

/*!
  \fn void HistoryView::ok(int item);
  emitted when the ok action has occured, contains history index at the time of close
*/

/*!
  \fn void HistoryView::cancel();
  emitted when the cancel action has occured
*/

} // namespace WRT