browsercore/appfw/Api/Views/WindowView.cpp
author hgs
Tue, 29 Jun 2010 00:46:29 -0400
changeset 3 0954f5dd2cd0
parent 0 1450b09d0cfd
child 12 afcd8e6d025b
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 "WindowView_p.h"
#include "WindowView.h"

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

#include <QDebug>

#define WINDOWVIEW_TIME_TO_TRANSITION 200
#define WINDOWVIEW_TIME_TO_ADD_NEXTPAGE 100
#define WINDOWVIEW_MAX_NUM_WINDOWS 5
namespace WRT {


WindowViewPrivate::WindowViewPrivate(WebPageController * pageMgr,
                                       QWidget* parent) :
    m_flowInterface(0),
    m_widgetParent(parent),
    m_graphicsWidgetParent(0),
    m_pageManager(pageMgr),
    m_mode(0),
    m_state(0)
{
    Q_ASSERT(m_pageManager);
    init();
}

WindowViewPrivate::WindowViewPrivate(WebPageController * pageMgr,
                                       QGraphicsWidget* parent) :
    m_flowInterface(0),
    m_widgetParent(0),
    m_graphicsWidgetParent(parent),
    m_pageManager(pageMgr),
    m_mode(0),
    m_state(0)
{
    Q_ASSERT(m_pageManager);
    init();
}

WindowViewPrivate::~WindowViewPrivate()
{
    delete m_transTimer;
}

void WindowViewPrivate::init()
{
    // create the view's actions
    m_actionForward = new QAction("Forward", m_graphicsWidgetParent);
    m_actionForward->setObjectName("Forward");

    m_actionBack = new QAction("Back", m_graphicsWidgetParent);
    m_actionBack->setObjectName("Back");

    m_actionOK = new QAction("OK", m_graphicsWidgetParent);
    m_actionOK->setObjectName("OK");

    m_actionCancel = new QAction("Cancel", m_graphicsWidgetParent);
    m_actionCancel->setObjectName("Cancel");

    m_actionGoBack = new QAction("goBack", m_graphicsWidgetParent);
    m_actionGoBack->setObjectName("goBack");
    m_actionGoBack->setEnabled(true);

    m_actionAddWindow = new QAction("addWindow", m_graphicsWidgetParent);
    m_actionAddWindow->setObjectName("addWindow");

    m_actionDelWindow = new QAction("delWindow", m_graphicsWidgetParent);
    m_actionDelWindow->setObjectName("delWindow");

}

/*!
 * \class WindowView
 *
 * \brief The base class for the WindowViews
 *
 * This class provides the basic routines to enable navigation amoung multiple pages
 * known by WebPageController.
 *
 * Derived classes (such as WindowFlowView, and WindowLiteView) supply
 * the exact "FlowInterface" to be used, and rely on much of the base-class functionality
 * for signal/slots, extracting thumbnails for each page, etc.
 *
 */

/*!
  Basic WindowView constructor requires a PageManager to manage the pages
  and a parent QWidget

  @param mgr : WebPageController handle for this class
  @param parent : Widget parent for this class
*/
WindowView::WindowView(WebPageController * pageMgr,
                         QWidget* parent) :
    d(new WindowViewPrivate(pageMgr, parent))
{
    init();
}

/*!
  Basic WindowView constructor requires a PageManager to manage the pages
  and a parent QGraphicsWidget

  Note: This functionality is not yet tested
  @param mgr : WebPageController handle for this class
  @param parent : Graphics Widget parent for this class
  @see  WebPageController
*/
WindowView::WindowView(WebPageController * pageMgr,
                         QGraphicsWidget* parent) :
    d(new WindowViewPrivate(pageMgr, parent))
{
    init();
}

WindowView::~WindowView()
{
//TODO: restoreSlides();
    delete d;
}

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

/*!
  Return the view's Forward QAction
  For scrolling the window view forwards
  @return forward public action
*/
QAction * WindowView::getActionForward()
{
    return d->m_actionForward;
}

/*!
  Return the view's Back QAction
  For scrolling the window view backwards
  @return  back public action
*/
QAction * WindowView::getActionBack()
{
    return d->m_actionBack;
}

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

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

/*!
  Return the view's add window QAction
  For adding a new window
  @return handle to addWindow action
*/
QAction *  WindowView::getActionAddWindow()
{
    return d->m_actionAddWindow;
}

/*!
  Return the view's delete window QAction
  For deleting a window. This will be dimmed for the last window
  @return  handle to deleteWindow action
*/
QAction *  WindowView::getActionDelWindow()
{
    return d->m_actionDelWindow;
}

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

/*!
  Return the title of this view for display
  @return Title String
*/
QString WindowView::title() const
{
    QString title =  qtTrId("txt_browser_windows_windows");

    if(d->m_flowInterface && d->m_pageList)
    {
        int centerIndex = d->m_flowInterface->centerIndex();
        if(centerIndex >= 0 && centerIndex < d->m_pageList->count())
        {
            QString pagetitle(d->m_pageList->at(centerIndex)->mainFrame()->title());
            if(pagetitle.isEmpty())
                title += qtTrId("txt_browser_windows_new_window");
            else
                title += pagetitle;
        }
    }
    return title;
}

/*!
  Test if this  view is active or not
  @return true if view is active else false
*/
bool WindowView::isActive()
{
    return (d->m_state == WindowViewActive ? true : false);
}


/*!
  Return the list of public QActions most relevant to the view's current context
  (most approptiate for contextual menus, etc.
  @ return list of public actions for this view
*/
QList<QAction*> WindowView::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_actionGoBack <<
        d->m_actionOK <<
        d->m_actionCancel <<
        d->m_actionAddWindow <<
        d->m_actionDelWindow;
    return contextList;
}

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

    if(!d->m_flowInterface)
        return;

    d->m_flowInterface->resize(d->m_windowViewSize);
    d->m_flowInterface->init();

    updateWindows();
    setCenterIndex(d->m_pageManager->currentPage());
    updateActions();

    // now forward flow interface's signals
    connect(d->m_flowInterface, SIGNAL(ok(int)), this, SLOT(okTriggered(int)));
    connect(d->m_flowInterface, SIGNAL(cancel()), this, SIGNAL(cancel()));
    connect(d->m_flowInterface, SIGNAL(centerIndexChanged(int)), this, SLOT(changedCenterIndex(int)));
    connect(d->m_flowInterface, SIGNAL(removed(int)), this, SLOT(delPage(int)));
    connect(d->m_transTimer, SIGNAL(timeout()), this, SLOT(endAnimation()));

    if (d->m_mode ==  WindowViewModeTransition ) {

        //qDebug() << "Connect to pageCreated " ;
        connect(d->m_pageManager, SIGNAL(creatingPage(WRT::WrtBrowserContainer*)), this, SLOT(onPageCreated(WRT::WrtBrowserContainer*)));
    }

    // FIXME: temporal fix the resize & performance issue caused by the new QGraphicsItem architecture
    widget()->installEventFilter(this);

    d->m_flowInterface->prepareStartAnimation();
    d->m_flowInterface->show();
    d->m_flowInterface->runStartAnimation();

    d->m_state = WindowViewActive;
}

/*!
  deactivate the view's resources. Could be connected by client to view visibility
*/
void WindowView::deactivate()
{
    //qDebug() << "deactivate " << d->m_mode;
    Q_ASSERT(d->m_state == WindowViewActive);

    if(!d->m_flowInterface)
        return;

    // disconnect signals
    disconnect(d->m_flowInterface, SIGNAL(ok(int)), this, SLOT(okTriggered(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(changedCenterIndex(int)));
    disconnect(d->m_flowInterface, SIGNAL(removed(int)), this, SLOT(delPage(int)));
    disconnect(d->m_transTimer, SIGNAL(timeout()), this, SLOT(endAnimation()));

    if (d->m_mode ==  WindowViewModeTransition ) {
        //qDebug() << "========Disconnect pageCreated ";
        disconnect(d->m_pageManager, SIGNAL(creatingPage(WRT::WrtBrowserContainer*)), this, SLOT(onPageCreated(WRT::WrtBrowserContainer*)));
        // Check if new pages list is empty  - assert  d->m_newPages.count()
    }
    widget()->removeEventFilter(this);

    // Hide and delete flowinterface later when told
    d->m_pageList = NULL;

    // Only needed when using QWidget based view
    //m_proxyWidget->setWidget(0);
    //delete m_proxyWidget;
    //m_proxyWidget = 0;

    // Hide and delete flowinterface
    d->m_flowInterface->hide();
    d->m_flowInterface->deleteLater();
    d->m_flowInterface = NULL;

    d->m_mode =  WindowViewModeNormal;
    d->m_state = WindowViewNotActive;

}

void WindowView::init()
{
    d->m_transTimer = new QTimer(this);

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

    // connect creation signals
    connect(d->m_actionAddWindow, SIGNAL(triggered()), this, SLOT(addPage()));
    connect(d->m_actionDelWindow, SIGNAL(triggered()), this, SLOT(delPage()));
}

void WindowView::setMode(Mode m)
{
    d->m_mode = m;
}

void WindowView::setSize(QSize& size)
{
    d->m_windowViewSize = size;
}

void WindowView::setCenterIndex()
{
    WrtBrowserContainer * p  = d->m_pageManager->currentPage();
    setCenterIndex(p);
}

void WindowView::setCenterIndex(int i)
{
    if(d->m_flowInterface)
        d->m_flowInterface->setCenterIndex(i);
}

void WindowView::setCenterIndex(WrtBrowserContainer * p)
{
    int currIndex = d->m_pageList->indexOf(p);
    if(currIndex >= 0)
        setCenterIndex(currIndex);
}

void WindowView::displayModeChanged(QString& newMode)
{
    //qDebug() << "WindowView::displayModeChanged:::" << newMode;
    // update page thumbnails
    QSize s = d->m_flowInterface->size().toSize();

    d->m_pageManager->resizeAndUpdatePageThumbnails(s);

    // update all the window images
    updateImages();

    // update the flow interface
    d->m_flowInterface->displayModeChanged(newMode);
}

void WindowView::updateImages()
{
    Q_ASSERT(d && d->m_flowInterface);

    // clear PictureFlow
    if (d->m_flowInterface->slideCount() != 0)
        d->m_flowInterface->clear();

    d->m_pageList = d->m_pageManager->allPages();
    for (int i = 0; i < d->m_pageList->count(); i++) {
        WrtBrowserContainer* window = d->m_pageList->at(i);
        QString title = window->pageTitle();
        if (title.isEmpty())
            title =  qtTrId("txt_browser_windows_new_window");

         QWebHistoryItem item = window->history()->currentItem();
         WebPageData data = item.userData().value<WebPageData>();
         QImage img = data.m_thumbnail;

         QSize size = window->webWidget()->size().toSize();
         QSize imgSize = img.size();
         float ratio = (float)size.width() / (float)size.height();
         float imgRatio = (float)imgSize.width() / (float)imgSize.height();
         if (imgRatio != ratio) {
             size.scale(imgSize, Qt::KeepAspectRatio);
             img = img.copy(0, 0, size.width(), size.height());
         }

         d->m_flowInterface->addSlide(img, title);
     }
     setCenterIndex(d->m_pageManager->currentPage());
}

void WindowView::updateWindows()
{
    if (!d->m_flowInterface)
        return;

    // update page thumbnails
    d->m_pageManager->updatePageThumbnails();

    // update all the images
    updateImages();
}

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

    d->m_flowInterface->showNext();
}

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

    d->m_flowInterface->showPrevious();
}

/*!
  animate from page "from" to page "to"
  @param from : from page handle
  @param to   : to page handle
*/
void  WindowView::animate(WrtBrowserContainer * from, WrtBrowserContainer * to)
{
    // fetch the indices for the given pages
    qDebug() << "This function is not implemented.";
}

void WindowView::changedCenterIndex(int index)
{
    switch (d->m_state) {
        case WindowViewActive:
            indexChangeInActiveState(index);
            break;
        case WindowViewAddPage:
            addPageCplt(index);
            break;
        case WindowViewDeletePage:
            delPageCplt(index);
            break;
        default:
            /* Shouldn't get here */
            break;
    }
}

void WindowView::indexChangeInActiveState(int index)
{
    if (d->m_mode ==  WindowViewModeNormal ) {
        WrtBrowserContainer* page = d->m_pageList->at(index);
        d->m_pageManager->setCurrentPage(page);

        /* Set the new page as the center page */
        emit centerIndexChanged(index);

        updateActions();
    }
    else {
        //qDebug() << "Start Adding pages " << "Pages in list" <<  d->m_newPages.count() << "Page added " << d->m_newPages.at(0);
        addPage(d->m_newPages.takeFirst());
    }
}


void WindowView::updateActions()
{
    int centerIndex = d->m_flowInterface->centerIndex();
    bool animActive = d->m_flowInterface->slideAnimationOngoing();

    d->m_actionForward->setEnabled( !animActive && (centerIndex < (d->m_pageManager->pageCount() - 1)) );
    d->m_actionBack->setEnabled( !animActive && (centerIndex != 0) );

    d->m_actionOK->setEnabled(!animActive);
    d->m_actionCancel->setEnabled(!animActive);

    d->m_actionDelWindow->setEnabled( !animActive && (d->m_pageManager->pageCount() > 1) );
    d->m_actionAddWindow->setEnabled(!animActive && (d->m_pageManager->pageCount() < WINDOWVIEW_MAX_NUM_WINDOWS));
}

void WindowView::okTriggered(int index)
{
    Q_UNUSED(index);
    Q_ASSERT(d->m_flowInterface);
    connect(d->m_flowInterface, SIGNAL(endAnimationCplt()), this, SLOT(okTriggeredCplt()));
    d->m_flowInterface->runEndAnimation();
}

void WindowView::okTriggeredCplt()
{
    Q_ASSERT(d->m_flowInterface);

    disconnect(d->m_flowInterface, SIGNAL(endAnimationCplt()), this, SLOT(okTriggeredCplt()));
    int index = d->m_flowInterface->centerIndex();

    if(d->m_flowInterface && d->m_pageList)
    {
        if(index >= 0 && index < d->m_pageList->count())
        {
        	  WrtBrowserContainer* page = d->m_pageList->at(index);
        	  // If mainframe URL is empty, we are restoring page
        	  // Page needs to be reloaded
        	  if (page->mainFrame()->url().isEmpty()){
        	  	QWebHistoryItem item = page->history()->currentItem();
        	  	if (item.isValid()) page->history()->goToItem(item);
        	  }
            emit ok(d->m_pageList->at(index));
        }
    }
}

void WindowView::addPage(WrtBrowserContainer* pg)
{
    Q_ASSERT(d->m_flowInterface);

    //qDebug() << "WindowView::addPage: COUNT "<< d->m_newPages.count();
    if (d->m_flowInterface->slideAnimationOngoing() || (d->m_mode ==  WindowViewModeNormal && d->m_state == WindowViewAddPage))
        return;

    d->m_state = WindowViewAddPage;

    // insert an empty image after index
    // the insert function will activate the add-page animation which is built-in in FilmstripFlow
    QImage img;
    QString title= "";
    if (pg && !pg->mainFrame()->requestedUrl().isEmpty() ) {
         if (!pg->mainFrame()->title().isEmpty())
             title = pg->mainFrame()->title();
         else  if (!pg->mainFrame()->url().isEmpty() )
             title = d->m_pageManager->partialUrl(pg->mainFrame()->url());
         else
             title = d->m_pageManager->partialUrl(pg->mainFrame()->requestedUrl());

         //qDebug() << "WindowView::addPage - Title " << pg->mainFrame()->title() << "Url : "<<  pg->mainFrame()->url().toString()<< "Requested Url : " << pg->mainFrame()->requestedUrl().toString()  ;
    }

    int index = d->m_flowInterface->centerIndex();
    d->m_flowInterface->insert(index + 1, img, title);

    updateActions();
}

void WindowView::addPageCplt(int index)
{
    /* Adding a new page is completed when the index reaches the newly added index*/
    Q_ASSERT(d->m_state == WindowViewAddPage);


    //qDebug() << " WindowView::addPageCplt: index " << index << "add new page" << d->m_newPages.count();
    /* If new pages were added, show them before transitioning back to content view */
    if (d->m_newPages.count() ) {

        //qDebug() << " WindowView::addPageCplt: index " << index << "add new page" << d->m_newPages.count();
        QTimer::singleShot(WINDOWVIEW_TIME_TO_ADD_NEXTPAGE, this, SLOT(addNextPage()));

    }
    else {
        connect(d->m_flowInterface, SIGNAL(endAnimationCplt()), this, SLOT(addPageCplt()));

        // Start a timer so that the new blank window is shown before transition starts
        d->m_transTimer->start(WINDOWVIEW_TIME_TO_TRANSITION);

    }

    emit pageAdded();
}

void WindowView::addNextPage()
{
    //qDebug() << " WindowView::addNextPage " << d->m_newPages.count() << "Added Page " << d->m_newPages.at(0);
    addPage(d->m_newPages.takeFirst());
}

void WindowView::endAnimation()
{

    //qDebug() << "WindowView::endAnimation ";
    d->m_transTimer->stop();
    d->m_flowInterface->runEndAnimation();

}

void WindowView::addPageCplt()
{
    //qDebug() << "WindowView::addPageCplt() " << d->m_newPages.count();
    if (d->m_mode ==  WindowViewModeNormal ) {
        // open a new page
        WRT::WrtBrowserContainer* pg = d->m_pageManager->openPage();
    }
    int index = d->m_flowInterface->centerIndex();
    emit centerIndexChanged(index);

    disconnect(d->m_flowInterface, SIGNAL(endAnimationCplt()), this, SLOT(addPageCplt()));
    d->m_state = WindowViewActive;
    updateActions();

    if (d->m_mode ==  WindowViewModeTransition ) {
        emit newWindowTransitionComplete();
    }

    emit addPageComplete();
}

void WindowView::delPage()
{
    Q_ASSERT(d->m_flowInterface);

    if (d->m_flowInterface->slideAnimationOngoing())
        return;

    d->m_flowInterface->removeAt(d->m_flowInterface->centerIndex());
}

void WindowView::delPage(int index)
{
    Q_ASSERT(d->m_flowInterface);
    Q_ASSERT(index >= 0 && index < d->m_pageList->count());

    if (d->m_flowInterface->slideAnimationOngoing())
        return;

    d->m_state = WindowViewDeletePage;
    WrtBrowserContainer * p = d->m_pageList->at(index);
    d->m_pageManager->closePage(p);
    updateActions();
}

void WindowView::delPageCplt(int index)
{
    Q_ASSERT(d->m_state == WindowViewDeletePage);

    /* Update the actions */
    updateActions();

    /* Reset the state and newCenterPage */
    d->m_state = WindowViewActive;

    /* Emit centerIndexChanged signal */
    emit centerIndexChanged(d->m_flowInterface->centerIndex());
}


void WindowView::onPageCreated(WRT::WrtBrowserContainer *pg) {

    //qDebug() << "WindowView::onPageCreated" << pg << "Trans Timer active " <<  d->m_transTimer->isActive();
    if (d->m_transTimer->isActive()) {
        // Stop that timer and add the new page
        d->m_transTimer->stop();
        addPage(pg);
    }
    else {

        d->m_newPages.append(pg);
    }
}
int WindowView::pageCount() {

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

int WindowView::currentPageIndex() {

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

WindowViewJSObject:: WindowViewJSObject(WindowView* view, QWebFrame* webFrame, const QString& objectName)
  : ControllableViewJSObject(view, webFrame, objectName)
{
    connect(view,SIGNAL(pageAdded()),this,SIGNAL(pageAdded()));

}

/*!
  \fn void WindowView::centerIndexChanged(int index);
  emitted when the center index changed
  @param index :  newly changed index
*/

/*!
  \fn void WindowView::ok(int item);
  emitted when the ok action has occured, contains window index at the time of close
  @item   : index of the  where ok action was triggred
*/

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

} // namespace WRT