/***************************** LICENSE START ***********************************

 Copyright 2013 ECMWF and INPE. This software is distributed under the terms
 of the Apache License version 2.0. In applying this license, ECMWF does not
 waive the privileges and immunities granted to it by virtue of its status as
 an Intergovernmental Organization or submit itself to any jurisdiction.

 ***************************** LICENSE END *************************************/

#include "MvQPageView.h"

#include <QApplication>
#include <QDebug>
#include <QGraphicsRectItem>
#include <QGraphicsScene>
#include <QGraphicsSceneMouseEvent>
#include <QKeyEvent>
#include <QLinearGradient>
#include <QPainter>
#include <QUndoStack>

#include "MvRequest.h"

#include "MvQIconMimeData.h"
#include "MvQIconProvider.h"
#include "MvQMethods.h"

std::vector<std::string> MvQPageView::classes_;
QMap<MvQPageHandlerItem::HandlerType, QPixmap> MvQPageHandlerItem::pix_;
QMap<MvQPageHandlerItem::HandlerType, QPixmap> MvQPageHandlerItem::pixHover_;

//========================================
//
// MvQPageHandlerItem
//
//========================================

MvQPageHandlerItem::MvQPageHandlerItem(MvQPageSelectionItem* page, HandlerType type) :
    page_(page),
    type_(type),
    hover_(false)
{
    setFlag(ItemIsMovable);
    setFlag(ItemSendsGeometryChanges);
    setAcceptHoverEvents(true);

    // 12x12 pixmaps
    setupPixmap();

    bRect_ = QRectF(0, 0, 12, 12);
    float delta = 6;

    switch (type_) {
        case TopLeft:
            bRect_.moveTo(-2 * delta, -2 * delta);
            break;
        case TopMid:
            bRect_.moveTo(-delta, -2 * delta);
            break;
        case TopRight:
            bRect_.moveTo(0, -2 * delta);
            break;
        case RightMid:
            bRect_.moveTo(0, -delta);
            break;
        case BottomRight:
            break;
        case BottomMid:
            bRect_.moveTo(-delta, 0);
            break;
        case BottomLeft:
            bRect_.moveTo(-2 * delta, 0);
            break;
        case LeftMid:
            bRect_.moveTo(-2 * delta, -delta);
            break;
        default:
            break;
    }

    updatePosition();

    setParentItem(page_);
}

void MvQPageHandlerItem::setupPixmap()
{
    if (pix_.count() != 0)
        return;

    pix_[TopLeft] = QPixmap(":/desktop/cursor_bdiag.svg");
    pix_[TopMid] = QPixmap(":/desktop/cursor_vert.svg");
    pix_[TopRight] = QPixmap(":/desktop/cursor_fdiag.svg");
    pix_[RightMid] = QPixmap(":/desktop/cursor_horiz.svg");
    pix_[BottomRight] = pix_[TopLeft];
    pix_[BottomMid] = pix_[TopMid];
    pix_[BottomLeft] = pix_[TopRight];
    pix_[LeftMid] = pix_[RightMid];

    pixHover_[TopLeft] = QPixmap(":/desktop/cursor_bdiag_hover.svg");
    pixHover_[TopMid] = QPixmap(":/desktop/cursor_vert_hover.svg");
    pixHover_[TopRight] = QPixmap(":/desktop/cursor_fdiag_hover.svg");
    pixHover_[RightMid] = QPixmap(":/desktop/cursor_horiz_hover.svg");
    pixHover_[BottomRight] = pixHover_[TopLeft];
    pixHover_[BottomMid] = pixHover_[TopMid];
    pixHover_[BottomLeft] = pixHover_[TopRight];
    pixHover_[LeftMid] = pixHover_[RightMid];
}

QRectF MvQPageHandlerItem::boundingRect() const
{
    return bRect_;
}

void MvQPageHandlerItem::paint(QPainter* painter, const QStyleOptionGraphicsItem*, QWidget*)
{
    if (!hover_)
        painter->drawPixmap(bRect_.topLeft(), pix_[type_]);
    else
        painter->drawPixmap(bRect_.topLeft(), pixHover_[type_]);
}

void MvQPageHandlerItem::updatePosition()
{
    QRectF r = page_->boundingRect();

    switch (type_) {
        case TopLeft:
            setPos(r.topLeft());
            break;
        case TopMid:
            setPos(r.center().x(), r.y());
            break;
        case TopRight:
            setPos(r.topRight());
            break;
        case RightMid:
            setPos(r.topRight().x(), r.center().y());
            break;
        case BottomRight:
            setPos(r.bottomRight());
            break;
        case BottomMid:
            setPos(r.center().x(), r.bottomRight().y());
            break;
        case BottomLeft:
            setPos(r.bottomLeft());
            break;
        case LeftMid:
            setPos(r.x(), r.center().y());
            break;
        default:
            break;
    }
}

QVariant MvQPageHandlerItem::itemChange(GraphicsItemChange change, const QVariant& value)
{
    /*QRectF r=page_->boundingRect();

    if(change == ItemPositionHasChanged)
        {
        switch(type_)
        {
        case TopMid: r.setTop(pos().y()); break;
        default: break;
        }

        page_->handlerMoved(r);
    }*/

    return QGraphicsItem::itemChange(change, value);
}

void MvQPageHandlerItem::mousePressEvent(QGraphicsSceneMouseEvent* event)
{
    update();

    QGraphicsItem::mousePressEvent(event);

    page_->handlerPressed(this);
}

void MvQPageHandlerItem::mouseMoveEvent(QGraphicsSceneMouseEvent* event)
{
    QRectF r = page_->boundingRect();
    QPointF pp = mapToParent(event->pos());

    switch (type_) {
        case TopLeft:
            r.setTopLeft(pp);
            break;
        case TopMid:
            setPos(QPointF(r.center().x(), pp.y()));
            r.setTop(pos().y());
            break;
        case TopRight:
            r.setTopRight(pp);
            break;
        case RightMid:
            setPos(QPointF(pp.x(), r.center().y()));
            r.setRight(pos().x());
            break;
        case BottomRight:
            r.setBottomRight(pp);
            break;
        case BottomMid:
            setPos(QPointF(r.center().x(), pp.y()));
            r.setBottom(pos().y());
            break;
        case BottomLeft:
            r.setBottomLeft(pp);
            break;
        case LeftMid:
            setPos(QPointF(pp.x(), r.center().y()));
            r.setLeft(pos().x());
            break;
        default:
            break;
    }

    page_->handlerMoved(this, r);
}

void MvQPageHandlerItem::mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
{
    QGraphicsItem::mouseReleaseEvent(event);
    page_->handlerReleased(this);
}


void MvQPageHandlerItem::hoverEnterEvent(QGraphicsSceneHoverEvent*)
{
    hover_ = true;
    update();
}

void MvQPageHandlerItem::hoverLeaveEvent(QGraphicsSceneHoverEvent*)
{
    hover_ = false;
    update();
}


//========================================
//
// MvQPageSelectionItem
//
//========================================

MvQPageSelectionItem::MvQPageSelectionItem(MvQPageView* view, MvQSuperPageItem* super) :
    view_(view),
    superPage_(super),
    handlerUsed_(false)

{
    pen_ = QPen(Qt::DashLine);
    pen_.setColor(Qt::black);
    brush_ = QBrush(QColor(0, 0, 255, 100));

    setAcceptDrops(true);

    setZValue(2);
    setParentItem(superPage_);
    createHandlers();
    hide();

    // setAcceptDrops(true);
}

QRectF MvQPageSelectionItem::boundingRect() const
{
    return bRect_;
}

void MvQPageSelectionItem::paint(QPainter* painter, const QStyleOptionGraphicsItem*, QWidget*)
{
    // painter->fillRect(bRect_,brush_);

    painter->setPen(pen_);
    painter->drawRect(bRect_);
}

void MvQPageSelectionItem::adjust(QRectF r)
{
    prepareGeometryChange();
    bRect_ = QRectF(0, 0, r.width(), r.height());
    setPos(r.topLeft());
    foreach (MvQPageHandlerItem* h, handlers_)
        h->updatePosition();
    update();
}

void MvQPageSelectionItem ::createHandlers()
{
    // Add handlersMvQPageItem::
    if (handlers_.isEmpty()) {
        MvQPageHandlerItem* item = nullptr;

        item = new MvQPageHandlerItem(this, MvQPageHandlerItem::TopLeft);
        handlers_ << item;

        item = new MvQPageHandlerItem(this, MvQPageHandlerItem::TopMid);
        handlers_ << item;

        item = new MvQPageHandlerItem(this, MvQPageHandlerItem::TopRight);
        handlers_ << item;

        item = new MvQPageHandlerItem(this, MvQPageHandlerItem::RightMid);
        handlers_ << item;

        item = new MvQPageHandlerItem(this, MvQPageHandlerItem::BottomRight);
        handlers_ << item;

        item = new MvQPageHandlerItem(this, MvQPageHandlerItem::BottomMid);
        handlers_ << item;

        item = new MvQPageHandlerItem(this, MvQPageHandlerItem::BottomLeft);
        handlers_ << item;

        item = new MvQPageHandlerItem(this, MvQPageHandlerItem::LeftMid);
        handlers_ << item;
    }
}

void MvQPageSelectionItem::handlerPressed(MvQPageHandlerItem*)
{
    oriRect_ = bRect_;
    oriPageRect_.clear();
    foreach (MvQPageItem* item, pages_)
        oriPageRect_ << item->paperRect();

    handlerUsed_ = true;
}

// Here rect is in item coordiantes
void MvQPageSelectionItem::handlerMoved(MvQPageHandlerItem* /*handler*/, QRectF rect)
{
    if (!handlerUsed_)
        return;

    prepareGeometryChange();

    QRectF oriRect = mapToParent(bRect_).boundingRect();

    if (superPage_->adjustItemResize(this, rect)) {
        QPointF dp = rect.topLeft() - bRect_.topLeft();
        bRect_ = QRectF(0, 0, rect.width(), rect.height());
        setPos(pos() + dp);
    }

    foreach (MvQPageHandlerItem* h, handlers_)
        h->updatePosition();

    QRectF newRect = mapToParent(bRect_).boundingRect();

    foreach (MvQPageItem* item, pages_) {
        item->adjustSizeToSelector(newRect, oriRect);
    }
}

void MvQPageSelectionItem::handlerReleased(MvQPageHandlerItem*)
{
    if (oriRect_ != bRect_) {
        view_->pagesResized(pages_, oriPageRect_);
    }

    oriPageRect_.clear();

    handlerUsed_ = false;
}

void MvQPageSelectionItem::mousePressEvent(QGraphicsSceneMouseEvent* event)
{
    if (handlerUsed_)
        return;

    oriPos_ = pos();
    dragPos_ = mapToParent(event->pos());
}

void MvQPageSelectionItem::mouseMoveEvent(QGraphicsSceneMouseEvent* event)
{
    if (handlerUsed_)
        return;

    QPointF delta = mapToParent(event->pos()) - dragPos_;

    QPointF prevPos = pos();
    QPointF pp = pos() + delta;

    superPage_->adjustItemMove(this, pp);
    setPos(pp);
    update();

    if (superPage_->adjustItemMove(this, pp)) {
        setPos(pp);
        update();
    }

    delta = pos() - prevPos;
    foreach (MvQPageItem* item, pages_) {
        item->moveBy(delta);
    }

    dragPos_ += delta;
}

void MvQPageSelectionItem::mouseReleaseEvent(QGraphicsSceneMouseEvent*)
{
    if (handlerUsed_)
        return;

    if (oriPos_ != pos())
        view_->pagesMoved(pages_, pos() - oriPos_);

    oriPos_ = pos();

    ungrabMouse();
}


void MvQPageSelectionItem::selectionChanged()
{
    pages_.clear();

    if (!superPage_)
        return;

    foreach (QGraphicsItem* item, superPage_->childItems()) {
        if (item->isSelected() && item->type() == MvQ::PageItemType)
            pages_ << dynamic_cast<MvQPageItem*>(item);
    }

    if (pages_.count() == 0) {
        hide();
    }
    else {
        QRectF br;

        QRectF p = pages_.at(0)->boundingRect();
        br = pages_.at(0)->mapToParent(p).boundingRect();
        for (int i = 1; i < pages_.count(); i++) {
            p = pages_.at(i)->boundingRect();
            br = br.united(pages_.at(i)->mapToParent(p).boundingRect());
        }

        adjust(br);

        show();
    }
}

void MvQPageSelectionItem::pagePressed(MvQPageItem* item, QGraphicsSceneMouseEvent* event)
{
    if (pages_.count() == 1 && pages_.at(0) == item) {
        oriPos_ = pos();
        // Event is valid for item!!
        dragPos_ = item->mapToParent(event->pos());

        setSelected(true);
        grabMouse();
    }
}


void MvQPageSelectionItem::dropEvent(QGraphicsSceneDragDropEvent* event)
{
    if (event->mimeData()->hasFormat("metview/icon")) {
        const auto* mimeData = qobject_cast<const MvQIconMimeData*>(event->mimeData());

        if (!mimeData) {
            return;
        }

        IconObjectH obj = mimeData->dragObject();

        if (obj && MvQPageView::matchClass(obj->className())) {
            foreach (MvQPageItem* item, pages_) {
                item->setViewIcon(obj);
            }
        }
    }
}

//========================================
//
// MvQSubPageItem
//
//========================================

MvQSubPageItem::MvQSubPageItem(MvQPageItem* page) :
    page_(page)
{
}

//========================================
//
// MvQPageItem
//
//========================================

MvQPageItem::MvQPageItem(MvQPageView* view, QRectF rect, MvQSuperPageItem* superPage) :
    view_(view),
    paperRect_(rect),
    superPage_(superPage),
    viewIcon_(nullptr),
    mouseMove_(false)
{
    bRect_ = QRectF(0, 0,
                    0.01 * paperRect_.width() * superPage_->boundingRect().width(),
                    0.01 * paperRect_.height() * superPage_->boundingRect().height());

    setPos(0.01 * paperRect_.x() * superPage_->boundingRect().width(),
           0.01 * paperRect_.y() * superPage_->boundingRect().height());

    setAcceptDrops(true);
    // setFlag(ItemIsMovable);
    setFlag(QGraphicsItem::ItemIsSelectable);
    setFlag(QGraphicsItem::ItemIsFocusable);
    // setFlag(ItemSendsGeometryChanges);

    pen_ = QPen(Qt::black);
    // pen_=QPen(QColor(8,54,146),1);
    pen_.setCosmetic(true);

    // brush_=QBrush(QColor(235,235,235,170));
    brush_ = QBrush(QColor(222, 230, 240, 160));

    selectionPen_ = QPen(Qt::black);
    selectionPen_.setCosmetic(true);
    selectionPen_.setStyle(Qt::DotLine);

    subPen_ = QPen(Qt::blue);
    subPen_.setCosmetic(true);
    subPen_.setStyle(Qt::DashLine);
}

QRectF MvQPageItem::boundingRect() const
{
    return bRect_;
}

void MvQPageItem::paint(QPainter* painter, const QStyleOptionGraphicsItem*, QWidget*)
{
    if (sub_.count() == 0) {
        painter->fillRect(bRect_, brush_);
    }
    else {
        painter->setPen(subPen_);

        float w = bRect_.width();
        float h = bRect_.height();

        for (int i = 0; i < sub_.count(); i++) {
            QRectF subR = sub_[i].second;
            QRectF sr(subR.x() * w / 100.,
                      subR.y() * h / 100.,
                      subR.width() * w / 100.,
                      subR.height() * h / 100.);

            painter->fillRect(sr, brush_);
            painter->drawRect(sr);
        }
    }

    painter->setPen((isSelected() == true) ? selectionPen_ : pen_);
    painter->drawRect(bRect_);

    if (!viewPix_.isNull()) {
        QFont font;
        QFontMetrics fm(font);

        float pw = viewPix_.width();
        float ph = viewPix_.height();

        if (pw < bRect_.width() - 8 && ph < bRect_.height() - 8) {
            QPoint targetPos(bRect_.center().x() - 0.5 * pw,
                             bRect_.center().y() - 0.5 * ph);

            painter->drawPixmap(targetPos, viewPix_);

            QString name = QString::fromStdString(viewIcon_->name());
            int tw = MvQ::textWidth(fm, name);
            float tx = bRect_.center().x() - tw / 2;
            float ty = bRect_.center().y() + 0.5 * ph + 3 + fm.height();

            painter->setPen(Qt::black);

            if (tw < bRect_.width() - 6 && ty < bRect_.bottom() - 4) {
                painter->drawText(tx, ty, name);
            }
        }
        else {
            pw = viewPixHalf_.width();
            ph = viewPixHalf_.height();

            if (pw < bRect_.width() - 8 && ph < bRect_.height() - 8) {
                QPoint targetPos(bRect_.center().x() - 0.5 * pw,
                                 bRect_.center().y() - 0.5 * ph);

                painter->drawPixmap(targetPos, viewPixHalf_);
            }
        }
    }
}

QVariant MvQPageItem::itemChange(GraphicsItemChange change, const QVariant& value)
{
    if (change == ItemSelectedHasChanged) {
        view_->pageSelected(this);
    }

    return QGraphicsItem::itemChange(change, value);
}

void MvQPageItem::mousePressEvent(QGraphicsSceneMouseEvent* event)
{
    QGraphicsItem::mousePressEvent(event);
    QGraphicsItem::mouseReleaseEvent(event);
    view_->pagePressed(this, event);
}

void MvQPageItem::keyPressEvent(QKeyEvent* event)
{
    // qDebug() << "key" << event->key();
    if (event->key() == Qt::Key_Backspace || event->key() == Qt::Key_Delete) {
        // qDebug() <<  "delete item";
    }
}

void MvQPageItem::setViewIcon(IconObjectH obj)
{
    viewIcon_ = obj;

    if (viewIcon_) {
        viewPix_ = MvQIconProvider::pixmap(viewIcon_, 32);
        viewPixHalf_ = MvQIconProvider::pixmap(viewIcon_, 16);
    }
    else {
        viewPix_ = QPixmap();
        viewPixHalf_ = QPixmap();
    }

    update();
}


void MvQPageItem::adjustSize()
{
    prepareGeometryChange();

    bRect_ = QRectF(0, 0,
                    0.01 * paperRect_.width() * superPage_->boundingRect().width(),
                    0.01 * paperRect_.height() * superPage_->boundingRect().height());

    setPos(0.01 * paperRect_.x() * superPage_->boundingRect().width(),
           0.01 * paperRect_.y() * superPage_->boundingRect().height());

    // foreach(MvQPageHandlerItem *h,handlers_)
    //   	h->updatePosition();
}

void MvQPageItem::adjustPaperRect()
{
    float w = superPage_->boundingRect().width();
    float h = superPage_->boundingRect().height();

    paperRect_ = QRectF(100. * pos().x() / w,
                        100. * pos().y() / h,
                        100. * bRect_.width() / w,
                        100. * bRect_.height() / h);
}

QRectF MvQPageItem::rectToSelector(QRectF rectNew, QRectF rectOri)
{
    QRectF itemRect = mapToParent(boundingRect()).boundingRect();

    float hRatio = rectNew.height() / rectOri.height();
    float wRatio = rectNew.width() / rectOri.width();

    float top = rectNew.top() + (itemRect.top() - rectOri.top()) * hRatio;
    float bottom = rectNew.bottom() - (rectOri.bottom() - itemRect.bottom()) * hRatio;
    float left = rectNew.left() + (itemRect.left() - rectOri.left()) * wRatio;
    float right = rectNew.right() - (rectOri.right() - itemRect.right()) * wRatio;

    return {left, top, right - left, bottom - top};
}


void MvQPageItem::adjustSizeToSelector(QRectF rectNew, QRectF rectOri)
{
    /*QRectF itemRect=mapToParent(boundingRect()).boundingRect();

    float hRatio=rectNew.height()/rectOri.height();
    float wRatio=rectNew.width()/rectOri.width();

    float top=rectNew.top()+(itemRect.top()-rectOri.top())*hRatio;
    float bottom=rectNew.bottom()-(rectOri.bottom()-itemRect.bottom())*hRatio;
    float left=rectNew.left()+(itemRect.left()-rectOri.left())*wRatio;
    float right=rectNew.right()-(rectOri.right()-itemRect.right())*wRatio;

    itemRect=QRectF(left,top,right-left,bottom-top);*/

    QRectF itemRect = rectToSelector(rectNew, rectOri);

    resize(itemRect);
}


void MvQPageItem::resize(QRectF rect)
{
    prepareGeometryChange();

    // QPointF dp=bRect_.topLeft()-rect.topLeft();
    bRect_ = QRectF(0, 0, rect.width(), rect.height());
    setPos(rect.topLeft());

    adjustPaperRect();

    /*float w=superPage_->boundingRect().width();
    float h=superPage_->boundingRect().height();

    QRectF oriRect=paperRect_;

    paperRect_=QRectF(100.*pos().x()/w,
              100.*pos().y()/h,
              100.*rect.width()/w,
              100.*rect.height()/h);*/
}

void MvQPageItem::moveBy(QPointF delta)
{
    prepareGeometryChange();
    setPos(pos() + delta);
    adjustPaperRect();
}


void MvQPageItem::dropEvent(QGraphicsSceneDragDropEvent* event)
{
    if (event->mimeData()->hasFormat("metview/icon")) {
        const auto* mimeData = qobject_cast<const MvQIconMimeData*>(event->mimeData());

        if (!mimeData) {
            return;
        }

        IconObjectH obj = mimeData->dragObject();

        if (obj && MvQPageView::matchClass(obj->className())) {
            setViewIcon(obj);
            // view_->pageResized();
        }
    }
}

void MvQPageItem::setPaperRect(QRectF pr)
{
    paperRect_ = pr;
    adjustSize();
}

void MvQPageItem::paperRect(double& top, double& left, double& bottom, double& right)
{
    top = paperRect_.y();
    left = paperRect_.x();
    bottom = paperRect_.bottomLeft().y();
    right = paperRect_.topRight().x();
}

void MvQPageItem::addSubPaperRect(MvQPageItem* item, QRectF r)
{
    float xr = paperRect_.width();
    float yr = paperRect_.height();

    QRectF sp(100. * (r.x() - paperRect_.x()) / xr,
              100. * (r.y() - paperRect_.y()) / yr,
              100. * r.width() / xr,
              100. * r.height() / yr);

    sub_ << qMakePair(item, sp);
}

void MvQPageItem::addSubPaperRectInPageCoords(double x, double y, double w, double h)
{
    sub_ << QPair<MvQPageItem*, QRectF>(0, QRectF(x, y, w, h));
}


QList<QRectF> MvQPageItem::subPaperRects() const
{
    QList<QRectF> lst;
    for (int i = 0; i < sub_.count(); i++)
        lst << sub_[i].second;

    return lst;
}


void MvQPageItem::clearSubPaperRects()
{
    sub_.clear();
}

MvQPageItem* MvQPageItem::subPage(int i) const
{
    return (i >= 0 && i < sub_.count()) ? (sub_[i].first) : 0;
}

QPointF MvQPageItem::paperToItem(QPointF pp)
{
    return superPage_->percentageToItem(pp);
}

QPointF MvQPageItem::itemToPaper(QPointF pp)
{
    return superPage_->itemToPercentage(pp);
}

//========================================
//
// MvQSuperPageItem
//
//========================================

MvQSuperPageItem::MvQSuperPageItem(MvQPageView* view, double w, double h,
                                   bool snap, float snapX, float snapY, bool grid) :
    view_(view),
    paperRect_(0., 0., w, h),
    bRect_(0., 0., w, h),
    scaling_(1.),
    snap_(snap),
    snapX_(snapX),
    snapY_(snapY),
    grid_(grid)
{
    gridPen_ = QPen(QColor(190, 190, 190));
    gridPen_.setStyle(Qt::DashLine);
}

QRectF MvQSuperPageItem::boundingRect() const
{
    return bRect_;
}

void MvQSuperPageItem::paint(QPainter* painter, const QStyleOptionGraphicsItem*, QWidget*)
{
    painter->fillRect(bRect_, Qt::white);

    painter->setPen(Qt::black);
    painter->drawRect(bRect_);

    if (grid_) {
        painter->setPen(gridPen_);

        for (float x = 0; x <= 100.; x += snapX_) {
            QPointF p1 = percentageToItem(QPointF(x, 0));
            QPointF p2 = percentageToItem(QPointF(x, 100));
            painter->drawLine(p1, p2);
        }

        for (float y = 0; y <= 100.; y += snapY_) {
            QPointF p1 = percentageToItem(QPointF(0, y));
            QPointF p2 = percentageToItem(QPointF(100, y));
            painter->drawLine(p1, p2);
        }
    }
}

MvQPageItem* MvQSuperPageItem::addPage(double x, double y, double w, double h)
{
    QRectF rect(x, y, w, h);

    auto* item = new MvQPageItem(view_, rect, this);
    item->setParentItem(this);

    return item;
}


void MvQSuperPageItem::resize(double w, double h)
{
    paperRect_ = QRectF(0., 0., w, h);
}


void MvQSuperPageItem::adjustSize(QSize size)
{
    float wRatio = size.width() / paperRect_.width();
    float hRatio = size.height() / paperRect_.height();
    scaling_ = (wRatio < hRatio) ? wRatio : hRatio;

    prepareGeometryChange();

    bRect_.setSize(paperRect_.size() * scaling_);

    foreach (MvQPageItem* p, pages())
        if (p)
            p->adjustSize();
}

QRectF MvQSuperPageItem::itemToPercentage(QRectF r)
{
    return QRectF(itemToPercentage(r.topLeft()),
                  itemToPercentage(r.bottomRight()));
}

QPointF MvQSuperPageItem::itemToPercentage(QPointF pp)
{
    return {100. * pp.x() / (paperRect_.width() * scaling_),
            100. * pp.y() / (paperRect_.height() * scaling_)};
}

QPointF MvQSuperPageItem::percentageToItem(QPointF pp)
{
    return {0.01 * pp.x() * paperRect_.width() * scaling_,
            0.01 * pp.y() * paperRect_.height() * scaling_};
}


QPointF MvQSuperPageItem::paperToItem(QPointF pp)
{
    return pp * scaling_;
}

QPointF MvQSuperPageItem::itemToPaper(QPointF pp)
{
    return pp / scaling_;
}


QPointF MvQSuperPageItem::snapToGrid(QPointF pp)
{
    if (!snap_)
        return pp;

    pp = itemToPercentage(pp);


    double xn = rint(pp.x() / snapX_);
    double yn = rint(pp.y() / snapY_);
    pp = percentageToItem(QPointF(xn * snapX_, yn * snapY_));

    if (pp.x() < 0)
        pp.setX(0);

    if (pp.x() > bRect_.width())
        pp.setX(bRect_.width());

    if (pp.y() < 0)
        pp.setY(0);

    if (pp.y() > bRect_.height())
        pp.setY(bRect_.height());

    return pp;
}

QRectF MvQSuperPageItem::snapToGrid(QRectF r)
{
    if (!snap_)
        return r;

    QPointF pp = itemToPercentage(r.topLeft());

    double xn = rint(pp.x() / snapX_);
    double yn = rint(pp.y() / snapY_);

    pp = percentageToItem(QPointF(xn * snapX_, yn * snapY_));
    r.moveTo(pp);

    if (r.left() < 0)
        r.moveLeft(0);

    if (r.right() > bRect_.width()) {
        pp = r.topLeft();
        QPointF delta(r.right() - bRect_.width(), 0);
        delta = itemToPercentage(delta);
        xn = ceil(delta.x() / snapX_);
        pp = itemToPercentage(pp);
        pp -= QPointF(xn * snapX_, 0);
        pp = percentageToItem(pp);
        r.moveLeft(pp.x());
    }

    if (r.top() < 0)
        r.moveTop(0);

    if (r.bottom() > bRect_.height()) {
        pp = r.bottomRight();
        QPointF delta(0, r.bottom() - bRect_.height());
        delta = itemToPercentage(delta);
        yn = ceil(delta.y() / snapY_);
        pp = itemToPercentage(pp);
        pp -= QPointF(0, yn * snapY_);
        pp = percentageToItem(pp);
        r.moveBottom(pp.y());
    }
    return r;
}

bool MvQSuperPageItem::adjustItemMove(QGraphicsItem* item, QPointF& pp)
{
    // r is in item coordinates

    QRectF r = mapFromItem(item, item->boundingRect()).boundingRect();
    r.moveTo(pp);

    bool adjusted = false;

    if (r.x() < bRect_.x()) {
        pp.setX(bRect_.x());
        adjusted = true;
    }
    if (r.topRight().x() > bRect_.topRight().x()) {
        pp.setX(bRect_.topRight().x() - r.width());
        adjusted = true;
    }
    if (r.y() < bRect_.y()) {
        pp.setY(bRect_.y());
        adjusted = true;
    }
    if (r.bottomRight().y() > bRect_.bottomRight().y()) {
        pp.setY(bRect_.bottomRight().y() - r.height());
        adjusted = true;
    }

    if (snap_) {
        r.moveTo(pp);
        r = snapToGrid(r);
        pp = r.topLeft();
        adjusted = true;
    }

    return adjusted;
}


bool MvQSuperPageItem::adjustItemResize(QGraphicsItem* item, QRectF& r)
{
    if (r.width() < 8 || r.height() < 8)
        return false;

    // r is in item coordinates!
    r = mapFromItem(item, r).boundingRect();

    r = bRect_.intersected(r);

    if (snap_) {
        QPointF tl = snapToGrid(r.topLeft());
        QPointF br = snapToGrid(r.bottomRight());

        r = QRectF(tl, br);
    }


    r = mapToItem(item, r).boundingRect();

    return true;
}

void MvQSuperPageItem::enableSnap(bool b)
{
    snap_ = b;
    update();
}

void MvQSuperPageItem::setSnap(float x, float y)
{
    bool changed = false;
    if (snapX_ != x) {
        snapX_ = x;
        changed = true;
    }
    if (snapY_ != y) {
        snapY_ = y;
        changed = true;
    }
    if (snap_ && changed)
        update();
}

void MvQSuperPageItem::enableGrid(bool b)
{
    grid_ = b;
    update();
}

QList<MvQPageItem*> MvQSuperPageItem::pages() const
{
    QList<MvQPageItem*> lst;
    foreach (QGraphicsItem* item, childItems()) {
        if (item->type() == MvQ::PageItemType)
            lst << dynamic_cast<MvQPageItem*>(item);
    }
    return lst;
}

//========================================
//
// MvQRulerItem
//
//========================================

MvQRulerItem::MvQRulerItem(MvQPageView* view, Qt::Orientation ori) :
    view_(view),
    orientation_(ori),
    pen_(Qt::black),
    subPen_(QColor(100, 100, 100)),
    halfLen_(7),
    subLen_(4)
{
    font_.setPointSize(6);

    QLinearGradient gr;
    gr.setCoordinateMode(QGradient::ObjectBoundingMode);
    gr.setStart(0, 0);

    if (orientation_ == Qt::Horizontal)
        gr.setFinalStop(0, 1);
    else
        gr.setFinalStop(1, 0);

    gr.setColorAt(0, QColor(252, 252, 252));
    gr.setColorAt(1, QColor(220, 220, 220));
    bg_ = QBrush(gr);
}

QRectF MvQRulerItem::boundingRect() const
{
    return bRect_;
}

void MvQRulerItem::paint(QPainter* painter, const QStyleOptionGraphicsItem*, QWidget*)
{
    painter->fillRect(bRect_, bg_);

    painter->setPen(pen_);
    painter->drawRect(bRect_);
    painter->setFont(font_);

    QFontMetrics fm(font_);
    int th = fm.ascent();

    if (orientation_ == Qt::Horizontal) {
        for (int x = 0; x <= 100; x += 10) {
            float xp = bRect_.width() * x / 100.;
            QString str = QString::number(x);
            QRectF br;

            if (x == 100)
                br = QRectF(xp - MvQ::textWidth(fm, str) - 1, 0, MvQ::textWidth(fm, str), th);
            else
                br = QRectF(xp + 2, 0, MvQ::textWidth(fm, str), th);

            painter->drawText(br, Qt::AlignHCenter, str);
            painter->drawLine(QPointF(xp, 2), QPointF(xp, bRect_.height()));
        }
        for (int x = 5; x <= 95; x += 10) {
            float xp = bRect_.width() * x / 100.;
            painter->drawLine(QPointF(xp, bRect_.height() - halfLen_), QPointF(xp, bRect_.height()));
        }

        painter->setPen(subPen_);

        for (int x = 1; x <= 99; x += 1) {
            if (x % 5 != 0) {
                float xp = bRect_.width() * x / 100.;
                painter->drawLine(QPointF(xp, bRect_.height() - subLen_), QPointF(xp, bRect_.height()));
            }
        }
    }
    else {
        for (int y = 0; y <= 100; y += 10) {
            float yp = bRect_.height() * y / 100.;
            QString str = QString::number(y);
            QRectF br;

            if (y == 100)
                br = QRectF(2, yp - th - 1, MvQ::textWidth(fm, str), th);
            else
                br = QRectF(2, yp + 2, MvQ::textWidth(fm, str), th);

            painter->drawText(br, Qt::AlignHCenter, str);
            painter->drawLine(QPointF(2, yp), QPointF(bRect_.width(), yp));
        }
        for (int y = 5; y <= 95; y += 10) {
            float yp = bRect_.height() * y / 100.;
            painter->drawLine(QPointF(bRect_.width() - halfLen_, yp), QPointF(bRect_.width(), yp));
        }

        painter->setPen(subPen_);

        for (int y = 1; y <= 99; y += 1) {
            if (y % 5 != 0) {
                float yp = bRect_.height() * y / 100.;
                painter->drawLine(QPointF(bRect_.width() - subLen_, yp), QPointF(bRect_.width(), yp));
            }
        }
    }
}

void MvQRulerItem::adjustSize()
{
    prepareGeometryChange();

    QRectF br = view_->superPage()->boundingRect();

    QFontMetrics fm(font_);
    int w = MvQ::textWidth(fm, "100") + 6;
    int h = fm.ascent() + 8;
    int d = (w < h) ? h : w;

    if (orientation_ == Qt::Horizontal) {
        setPos(br.x(), br.y() - d - 4);
        bRect_ = QRectF(0, 0, br.width(), d);
    }
    else {
        setPos(br.x() - d - 4, br.y());
        bRect_ = QRectF(0, 0, d, br.height());
    }
}

//========================================
//
// MvQPageView
//
//========================================

MvQPageView::MvQPageView(const std::vector<std::string>& classes, QUndoStack* undoStack, QWidget* parent) :
    QGraphicsView(parent),
    undoStack_(undoStack),
    scene_(nullptr),
    superPage_(nullptr),
    selector_(nullptr),
    rulerH_(nullptr),
    rulerV_(nullptr)
{
    classes_ = classes;

    setBackgroundBrush(QColor(125, 124, 123));

    scene_ = new QGraphicsScene(this);
    setScene(scene_);

    setDragMode(QGraphicsView::RubberBandDrag);
}

void MvQPageView::selection()
{
    if (!superPage_)
        return;

    if (!selector_) {
        selector_ = new MvQPageSelectionItem(this, superPage_);
    }

    selector_->selectionChanged();

    emit selectionChanged(selector_->pages().count());
}

void MvQPageView::pageSelected(MvQPageItem*)
{
    selection();
}

void MvQPageView::pagePressed(MvQPageItem* item, QGraphicsSceneMouseEvent* event)
{
    if (selector_)
        selector_->pagePressed(item, event);
}

void MvQPageView::clear()
{
    if (superPage_) {
        scene()->removeItem(superPage_);
        delete superPage_;
        superPage_ = nullptr;
        scene()->removeItem(rulerH_);
        delete rulerH_;
        rulerH_ = nullptr;
        scene()->removeItem(rulerV_);
        delete rulerV_;
        rulerV_ = nullptr;

        selector_ = nullptr;
        undoStack_->clear();
    }
}

void MvQPageView::clearPages()
{
    if (superPage_) {
        foreach (QGraphicsItem* item, superPage_->childItems()) {
            scene()->removeItem(item);
            delete item;
        }
    }
}

bool MvQPageView::matchClass(const std::string& cname)
{
    for (const auto& classe : classes_) {
        if (classe == cname)
            return true;
    }

    return false;
}

void MvQPageView::setSuperPage(double width, double height, bool snap, float snapX, float snapY, bool grid)
{
    if (!superPage_) {
        superPage_ = new MvQSuperPageItem(this, width, height, snap, snapX, snapY, grid);
        scene_->addItem(superPage_);
        rulerH_ = new MvQRulerItem(this, Qt::Horizontal);
        scene_->addItem(rulerH_);
        rulerV_ = new MvQRulerItem(this, Qt::Vertical);
        scene_->addItem(rulerV_);

        adjustSize();
    }
    else {
        if (superPage_->paperRect().width() != width ||
            superPage_->paperRect().height() != height) {
            superPage_->resize(width, height);
            adjustSize();
        }
    }
}

void MvQPageView::resizeEvent(QResizeEvent* event)
{
    QGraphicsView::resizeEvent(event);
    adjustSize();
}

void MvQPageView::adjustSize()
{
    if (!superPage_ || !rulerH_ || !rulerV_)
        return;

    int dh = rulerH_->boundingRect().height();
    int dw = rulerV_->boundingRect().width();

    QSize size = maximumViewportSize();
    size -= QSize(20 + dw + 4, dh + 4 + 20);

    superPage_->adjustSize(size);
    rulerH_->adjustSize();
    rulerV_->adjustSize();

    // Update selector
    selection();

    // Set the scenerect
    QRectF br = superPage_->boundingRect();
    br.adjust(-dw - 4, -dh - 4, 0, 0);
    scene_->setSceneRect(br);
}

MvQPageItem* MvQPageView::addPage(double x, double y, double w, double h)
{
    if (!superPage_)
        return nullptr;

    auto* cmd = new MvQPageAddCommand(this, x, y, w, h);
    undoStack_->push(cmd);

    return cmd->page();
}

void MvQPageView::pagesResized(QList<MvQPageItem*> pages, QList<QRectF> oriPaperRects)
{
    auto* cmdParent = new MvQUndoCommand(this, nullptr);
    cmdParent->setText("resize");

    for (int i = 0; i < pages.count(); i++) {
        new MvQPageResizeCommand(this, pages[i], oriPaperRects[i], pages.at(i)->paperRect(), cmdParent);
    }

    undoStack_->push(cmdParent);

    emit changed();
}

void MvQPageView::pagesMoved(QList<MvQPageItem*> pages, const QPointF& delta)
{
    auto* cmdParent = new MvQUndoCommand(this, nullptr);
    cmdParent->setText("move");

    foreach (MvQPageItem* item, pages) {
        new MvQPageMoveCommand(this, item, delta, cmdParent);
    }

    undoStack_->push(cmdParent);

    emit changed();
}

void MvQPageView::duplicateSelection()
{
    if (!selector_ || !selector_->hasPages())
        return;

    auto* cmdParent = new MvQUndoCommand(this, nullptr);
    cmdParent->setText("duplicate");

    foreach (MvQPageItem* item, selector_->pages()) {
        new MvQPageAddCommand(this, item, cmdParent);
    }

    undoStack_->push(cmdParent);
}

void MvQPageView::deleteSelection()
{
    if (!selector_ || !selector_->hasPages())
        return;

    auto* cmdParent = new MvQUndoCommand(this, nullptr);
    cmdParent->setText("delete");

    foreach (MvQPageItem* item, selector_->pages()) {
        new MvQPageDeleteCommand(this, item, cmdParent);
    }

    undoStack_->push(cmdParent);
}

void MvQPageView::joinSelection()
{
    if (!selector_ || selector_->pages().count() < 2)
        return;

    auto* cmd = new MvQPageJoinCommand(this, selector_->pages());
    undoStack_->push(cmd);
}

void MvQPageView::splitSelection(int row, int column)
{
    if (!selector_ || !selector_->hasPages())
        return;

    auto* cmdParent = new MvQUndoCommand(this, nullptr);
    cmdParent->setText("split");

    foreach (MvQPageItem* item, selector_->pages()) {
        new MvQPageSplitCommand(this, item, row, column, cmdParent);
    }

    undoStack_->push(cmdParent);
}

void MvQPageView::expandSelection()
{
    if (!selector_ || !selector_->hasPages())
        return;

    auto* cmdParent = new MvQUndoCommand(this, nullptr);
    cmdParent->setText("expand");

    QRectF selRect = selector_->mapToParent(selector_->boundingRect()).boundingRect();
    QRectF expandRect = superPage_->boundingRect();

    foreach (MvQPageItem* item, selector_->pages()) {
        QRectF r = superPage_->itemToPercentage(item->rectToSelector(expandRect, selRect));
        new MvQPageExpandCommand(this, item, r, cmdParent);
    }

    undoStack_->push(cmdParent);
}

void MvQPageView::connectSelection()
{
    if (!selector_ || selector_->pages().count() < 2)
        return;

    auto* cmd = new MvQPageConnectCommand(this, selector_->pages());
    undoStack_->push(cmd);
}

void MvQPageView::disconnectSelection()
{
    if (!selector_)
        return;

    bool hasSub = false;
    foreach (MvQPageItem* item, selector_->pages()) {
        if (item->hasSubPaperRect()) {
            hasSub = true;
            break;
        }
    }

    if (!hasSub)
        return;

    auto* cmdParent = new MvQUndoCommand(this, nullptr);
    cmdParent->setText("disconnect");

    foreach (MvQPageItem* item, selector_->pages()) {
        if (item->hasSubPaperRect()) {
            new MvQPageDisconnectCommand(this, item, cmdParent);
        }
    }

    undoStack_->push(cmdParent);
}

void MvQPageView::selectAll()
{
    foreach (MvQPageItem* p, superPage_->pages())
        if (p)
            p->setSelected(true);
}

void MvQPageView::enableSnap(bool b)
{
    if (superPage_)
        superPage_->enableSnap(b);
}

void MvQPageView::setSnap(float x, float y)
{
    if (superPage_)
        superPage_->setSnap(x, y);
}

void MvQPageView::enableGrid(bool b)
{
    if (superPage_)
        superPage_->enableGrid(b);
}

QList<MvQPageItem*> MvQPageView::pages() const
{
    return (superPage_) ? superPage_->pages() : QList<MvQPageItem*>();
}

//============================================
//
// Commands
//
//=============================================

//------------------------
// Container commmand
//------------------------

MvQUndoCommand::MvQUndoCommand(MvQPageView* view, QUndoCommand* parent) :
    QUndoCommand(parent),
    view_(view)
{
}

void MvQUndoCommand::redo()
{
    QUndoCommand::redo();
    view_->selection();
}

void MvQUndoCommand::undo()
{
    QUndoCommand::undo();
    view_->selection();
}

//------------------
// Add page
//------------------

MvQPageAddCommand::MvQPageAddCommand(MvQPageView* view, float x, float y, float w, float h, QUndoCommand* parent) :
    MvQUndoCommand(view, parent),
    oriRect_(x, y, w, h)
{
    page_ = view_->superPage()->addPage(x, y, w, h);
    setText("Add");
}


MvQPageAddCommand::MvQPageAddCommand(MvQPageView* view, MvQPageItem* page, QUndoCommand* parent) :
    MvQUndoCommand(view, parent)

{
    oriRect_ = page->paperRect();
    page_ = view_->superPage()->addPage(oriRect_.x(), oriRect_.y(), oriRect_.width(), oriRect_.height());
    page_->setViewIcon(page->viewIcon());
    setText("Add");
}

void MvQPageAddCommand::redo()
{
    if (!page_->scene()) {
        page_->setParentItem(view_->superPage());
        page_->setPaperRect(oriRect_);
    }
}

void MvQPageAddCommand::undo()
{
    view_->scene()->removeItem(page_);
    view_->selection();
}

//------------------
// Delete page
//------------------

MvQPageDeleteCommand::MvQPageDeleteCommand(MvQPageView* view, MvQPageItem* page, QUndoCommand* parent) :
    MvQUndoCommand(view, parent),
    page_(page)

{
    setText("Delete");
}

void MvQPageDeleteCommand::redo()
{
    view_->scene()->removeItem(page_);
}

void MvQPageDeleteCommand::undo()
{
    if (!page_->scene()) {
        page_->setParentItem(view_->superPage());
    }
}


//------------------
// Resize page
//------------------

MvQPageResizeCommand::MvQPageResizeCommand(MvQPageView* view, MvQPageItem* page,
                                           const QRectF& fromRect, const QRectF& toRect, QUndoCommand* parent) :
    MvQUndoCommand(view, parent),
    page_(page),
    fromRect_(fromRect),
    toRect_(toRect)
{
}

void MvQPageResizeCommand::redo()
{
    if (toRect_ != page_->paperRect())
        page_->setPaperRect(toRect_);
}

void MvQPageResizeCommand::undo()
{
    page_->setPaperRect(fromRect_);
}

//------------------
// Expand page
//------------------

MvQPageExpandCommand::MvQPageExpandCommand(MvQPageView* view, MvQPageItem* page, QRectF toRect, QUndoCommand* parent) :
    MvQUndoCommand(view, parent),
    page_(page),
    fromRect_(page->paperRect()),
    toRect_(toRect)
{
}

void MvQPageExpandCommand::redo()
{
    page_->setPaperRect(toRect_);
}

void MvQPageExpandCommand::undo()
{
    page_->setPaperRect(fromRect_);
}

//------------------
// Move page
//------------------

MvQPageMoveCommand::MvQPageMoveCommand(MvQPageView* view, MvQPageItem* page, const QPointF& delta, QUndoCommand* parent) :
    MvQUndoCommand(view, parent),
    page_(page)
{
    toPos_ = page_->paperRect().topLeft();
    fromPos_ = toPos_ - page_->itemToPaper(delta);

    setText("Move");
}

void MvQPageMoveCommand::redo()
{
    page_->setPos(page_->paperToItem(toPos_));
}

void MvQPageMoveCommand::undo()
{
    page_->setPos(page_->paperToItem(fromPos_));
    page_->scene()->update();
}

//------------------
// Join pages
//------------------

MvQPageJoinCommand::MvQPageJoinCommand(MvQPageView* view, QList<MvQPageItem*> pages,
                                       QUndoCommand* parent) :
    MvQUndoCommand(view, parent),
    pages_(pages),
    parentItem_(nullptr)
{
    if (pages_.count() > 0) {
        firstOriRect_ = pages_.at(0)->paperRect();
        parentItem_ = pages_.at(0)->parentItem();
    }
    setText("Join");
}

void MvQPageJoinCommand::redo()
{
    MvQPageItem* first = nullptr;
    QRectF joinedRect;

    foreach (MvQPageItem* item, pages_) {
        if (!first) {
            first = item;
            joinedRect = item->paperRect();
        }
        else {
            joinedRect = joinedRect.united(item->paperRect());
            parentItem_->scene()->removeItem(item);
        }
    }

    if (first) {
        first->setPaperRect(joinedRect);
    }

    view_->selection();
}

void MvQPageJoinCommand::undo()
{
    MvQPageItem* first = nullptr;

    foreach (MvQPageItem* item, pages_) {
        if (!first) {
            first = item;
            item->setPaperRect(firstOriRect_);
        }
        else {
            item->setParentItem(parentItem_);
        }
    }

    view_->selection();
}


//------------------
// Split pages
//------------------

MvQPageSplitCommand::MvQPageSplitCommand(MvQPageView* view, MvQPageItem* page, int row, int column, QUndoCommand* parent) :
    MvQUndoCommand(view, parent),
    page_(page),
    row_(row),
    column_(column)
{
}

void MvQPageSplitCommand::redo()
{
    if ((row_ <= 1 && column_ <= 1) || row_ > 10 || column_ > 10)
        return;

    if (splitPages_.count() == 0) {
        QRectF r = page_->paperRect();
        double dx = r.width() / column_;
        double dy = r.height() / row_;

        for (int i = 0; i < row_; i++) {
            for (int j = 0; j < column_; j++) {
                MvQPageItem* p = view_->superPage()->addPage(r.x() + j * dx, r.y() + i * dy, dx, dy);
                splitPages_ << p;
                p->setViewIcon(page_->viewIcon());
            }
        }
    }
    else {
        foreach (MvQPageItem* item, splitPages_) {
            item->setParentItem(view_->superPage());
        }
    }

    view_->scene()->removeItem(page_);
}

void MvQPageSplitCommand::undo()
{
    foreach (MvQPageItem* item, splitPages_) {
        view_->scene()->removeItem(item);
    }

    page_->setParentItem(view_->superPage());
}


//------------------
// Connect pages
//------------------

MvQPageConnectCommand::MvQPageConnectCommand(MvQPageView* view, QList<MvQPageItem*> pages,
                                             QUndoCommand* parent) :
    MvQUndoCommand(view, parent),
    pages_(pages)
{
    if (pages_.count() > 0) {
        firstOriRect_ = pages_.at(0)->paperRect();
    }
    setText("connect");
}

void MvQPageConnectCommand::redo()
{
    MvQPageItem* first = nullptr;
    QRectF joinedRect;

    foreach (MvQPageItem* item, pages_) {
        if (!first) {
            first = item;
            joinedRect = item->paperRect();
        }
        else {
            joinedRect = joinedRect.united(item->paperRect());
        }
    }

    if (first) {
        first->setPaperRect(joinedRect);
        foreach (MvQPageItem* item, pages_) {
            if (item == first) {
                first->addSubPaperRect(first, firstOriRect_);
            }
            if (item != first) {
                first->addSubPaperRect(item, item->paperRect());
                view_->scene()->removeItem(item);
            }
        }
    }

    view_->selection();
}

void MvQPageConnectCommand::undo()
{
    MvQPageItem* first = nullptr;
    foreach (MvQPageItem* item, pages_) {
        if (!first) {
            first = item;
            item->setPaperRect(firstOriRect_);
        }
        else {
            item->setParentItem(view_->superPage());
        }
    }

    if (first)
        first->clearSubPaperRects();

    view_->selection();
}


//------------------
// Disconnect pages
//------------------

MvQPageDisconnectCommand::MvQPageDisconnectCommand(MvQPageView* view, MvQPageItem* page, QUndoCommand* parent) :
    MvQUndoCommand(view, parent),
    page_(page)
{
}

void MvQPageDisconnectCommand::redo()
{
    pages_.clear();

    QRectF pf = page_->paperRect();
    float w = pf.width();
    float h = pf.height();

    QList<QRectF> subR = page_->subPaperRects();

    for (int i = 0; i < subR.count(); i++) {
        QRectF pr(pf.x() + subR[i].x() * w * 0.01,
                  pf.y() + subR[i].y() * h * 0.01,
                  subR[i].width() * w * 0.01,
                  subR[i].height() * h * 0.01);

        MvQPageItem* item = page_->subPage(i);

        if (item) {
            pages_ << item;

            item->setPaperRect(pr);

            if (item != page_) {
                item->setViewIcon(page_->viewIcon());
                item->setParentItem(view_->superPage());
            }
        }
    }

    page_->clearSubPaperRects();

    view_->selection();
}

void MvQPageDisconnectCommand::undo()
{
    QRectF joinedRect;

    joinedRect = page_->paperRect();
    foreach (MvQPageItem* item, pages_) {
        if (item != page_) {
            joinedRect = joinedRect.united(item->paperRect());
        }
    }

    QRectF oriRect = page_->paperRect();
    page_->setPaperRect(joinedRect);

    foreach (MvQPageItem* item, pages_) {
        if (item == page_) {
            page_->addSubPaperRect(item, oriRect);
        }
        else {
            page_->addSubPaperRect(item, item->paperRect());
            view_->scene()->removeItem(item);
        }
    }

    view_->selection();
}
