#include "topwin8desktopgroup.h"
#include <QVariant>
#include <QDropEvent>
#include <QGridLayout>
#include <QUuid>
#include <QMimeData>
#include <QDrag>
#include <QLabel>
#include <QMenu>
#include <QPainter>
#include <QActionGroup>
#include <QFormLayout>
#include <QSpinBox>
#include <topcore/topcore.h>
#include <topcore/topclasspluginabs.h>
#include <tbaseutil/ttheme.h>
#include <tbaseutil/tdataparse.h>
#include <tbaseutil/tfileio.h>
#include <tbaseutil/tresource.h>
#include <tbaseutil/tdataresponse.h>
#include <twidget/tuiloaderdialog.h>
#include <twidget/tuiloader.h>
#include <twidget/tscrollarea.h>
#include <twidget/tmessagebox.h>
#include <twidget/tcombobox.h>
#include <twidget/ttableviewdialog.h>
#include <twidget/ttreeviewdialog.h>
#include <twidget/tmessagebar.h>
#include <tdatabaseutil/tsqlconnectionpoolv2.h>
#include <tdatabaseutil/tsqlqueryv2.h>
#include <tdatabaseutil/tsqlselectorv2.h>
#include "topwin8desktopitem.h"
#include "topdesktopitemabs.h"

enum WndSize
{
    WndSize_CellWidth = 64, // Cell是一个单元格
    WndSize_CellHeight = 64,
    WndSize_ItemsMargin = 6,
    WndSize_ItemsSpace  = 10,
    WndSize_ItemCalcSpace = 15,  // 拖拽时判断位置距离topleft,大概1/3处
};

class TopWin8DesktopGroupPrivate
{
    Q_DECLARE_PUBLIC(TopWin8DesktopGroup)

public:
    TopWin8DesktopGroupPrivate(TopWin8DesktopGroup *qptr);
    TScrollArea *mScrollArea;
    QWidget *mCenterWidget;
    QGridLayout *mGridLayout;
    QHBoxLayout *mHcenterLayout;
    QMap<QString, QString> mModuleRightMap;
    TopDesktopItemAbs::State state;
    TopDesktopItemAbs::ClickType clickType;
    QVariantMap mConfigDataVarMap;
    QList<TopDesktopItemAbs *> mItemsLst;
    QMenu *mGroupMenu;
    bool startDragBol;
    bool drawCurPosiRectBol;
    QRect curDroppableRect;
    QPoint pressPos;
    Qt::Orientation mItemPrivority;
    static QMap<QString, QString> i18NMap;
    const QString defaultBackground = "transparent";
    const QString defaultTitleColor = "white";

protected:
    TopWin8DesktopGroup * const q_ptr;
};

QMap<QString, QString> TopWin8DesktopGroupPrivate::i18NMap = {
    {"GroupName", QObject::tr("GroupName")},
    {"GroupName(English)", QObject::tr("GroupName(English)")},
    {"GroupName(Chinese Simplified)", QObject::tr("GroupName(Chinese Simplified)")},
    {"GroupName(Chinese Tranditional)", QObject::tr("GroupName(Chinese Tranditional)")},
    {"Icon Name", QObject::tr("Icon Name")},
    {"Title Color", QObject::tr("Title Color")},
    {"Background Color", QObject::tr("Background Color")},
    {"Size", QObject::tr("Size")},
    {"Top Left", QObject::tr("Top Left")},
    {"Top", QObject::tr("Top")},
    {"Top Right", QObject::tr("Top Right")},
    {"Left", QObject::tr("Left")},
    {"Center", QObject::tr("Center")},
    {"Right", QObject::tr("Right")},
    {"Bottom Left", QObject::tr("Bottom Left")},
    {"Bottom", QObject::tr("Bottom")},
    {"Bottom Right", QObject::tr("Bottom Right")},
    {"Absolute Position", QObject::tr("Absolute Position")},
    {"Dock Area", QObject::tr("Dock Area")},
    {"Dock Sequence", QObject::tr("Dock Sequence")}
};

TopWin8DesktopGroupPrivate::TopWin8DesktopGroupPrivate(TopWin8DesktopGroup *qptr) :
    mScrollArea(NULL),
    mCenterWidget(NULL),
    mGridLayout(NULL),
    mGroupMenu(NULL),
    startDragBol(false),
    drawCurPosiRectBol(false),
    mItemPrivority(Qt::Horizontal),
    q_ptr(qptr)
{

}

TopWin8DesktopGroup::TopWin8DesktopGroup(QWidget *iParent) :
    QGroupBox(iParent),
    d_ptr(new TopWin8DesktopGroupPrivate(this))
{
    Q_D(TopWin8DesktopGroup);
    this->setProperty("SS", "DESKTOPGROUP");
    d->mScrollArea = new TScrollArea(this);
    d->mCenterWidget = new QWidget(d->mScrollArea);
    d->mCenterWidget->setObjectName("CENTERWIDGET");
    d->mScrollArea->setWidget(d->mCenterWidget);
    d->mScrollArea->setWidgetResizable(true);
    d->mScrollArea->setStyleSheet(QString(".TScrollArea{background:transparent; border-width:0px;}"
                                          ".QWidget#CENTERWIDGET{background:%1;}").arg(d->defaultBackground));

    QHBoxLayout *hLayout = new QHBoxLayout(this);
    hLayout->setMargin(0);
    hLayout->setSpacing(0);
    hLayout->addWidget(d->mScrollArea, 1);

    d->mGridLayout = new QGridLayout(0);
    d->mGridLayout->setMargin(WndSize_ItemsMargin);
    d->mGridLayout->setSpacing(0);

    QHBoxLayout *hCenterLayout = new QHBoxLayout(d->mCenterWidget);
    hCenterLayout->setMargin(0);
    hCenterLayout->setSpacing(0);
    hCenterLayout->addLayout(d->mGridLayout);
    d->mHcenterLayout = hCenterLayout;
    setAcceptDrops(true);

    this->setStyleSheet(QString("QGroupBox[SS=\"DESKTOPGROUP\"]{border:none;font-size:18px;margin-top: 24px;} "
                                "QGroupBox[SS=\"DESKTOPGROUP\"]::title { subcontrol-origin: margin;subcontrol-position:top left;padding-left: 5px;color:%1;}")
                        .arg(d->defaultTitleColor));
}

TopWin8DesktopGroup::~TopWin8DesktopGroup()
{
    Q_D(TopWin8DesktopGroup);
    delete d->mGridLayout;
}

void TopWin8DesktopGroup::doLayout()
{
    Q_D(TopWin8DesktopGroup);

    // 1.检查初值
    int colSpanInt = colSpan();
    int rowSpanInt = rowSpan();
    if (colSpanInt <= 0) colSpanInt = 1;
    if (rowSpanInt <= 0) rowSpanInt = 1;

    int cellWidthInt = WndSize_CellWidth;
    setCellWidth(cellWidthInt);

    int cellHeightInt = WndSize_CellHeight;
    setCellHeight(cellHeightInt);

    // 2.对分组大小和布局调整
    while (d->mGridLayout->count() > 0)
    {
        d->mGridLayout->removeItem(d->mGridLayout->itemAt(0));
    }
    d->mScrollArea->setFixedSize(cellWidthInt * colSpanInt + d->mGridLayout->spacing() * (colSpanInt - 1) + 2 * d->mGridLayout->margin() + 3,
                                 cellHeightInt * rowSpanInt + d->mGridLayout->spacing() * (rowSpanInt - 1) + 2 * d->mGridLayout->margin()+ 3);

    // 3.计算item位置
    QPoint  itemRowColPoint;
    QRect   itemRect;
    QPoint  layoutedItemRowColPoint;
    QList<TopDesktopItemAbs *> layoutedItemsLst;

    layoutedItemsLst.clear();

    QList<TopDesktopItemAbs *> itemsLst = d->mItemsLst;

    foreach (TopDesktopItemAbs *item, itemsLst) {                            // point: x表示行,y表示列
        itemRowColPoint = posStr2Point(item->config("position").toString()); // rect : x表示列(左边距离),y表示行
        itemRect = QRect(QPoint(itemRowColPoint.y(), itemRowColPoint.x()),
                         QSize(item->colSpan(), item->rowSpan()));
        item->blockSignals(true);
        // 3.1 是否超出最大宽度
        if (isBeyondPlacedArea(itemRect, colSpanInt) && itemRect.x() != 0)
        {
            // 下移一行
            itemRect.moveTo(0, itemRect.y() + 1);
        }

        // 3.2 检测QRect是否和已经布局的Item碰撞
        bool isPreviousCollisionBol = false;
        while (isCollisionWithLayoutedItems(itemRect, layoutedItemsLst, &isPreviousCollisionBol))
        {
            // 后面的位置Item下移一格
            if (isPreviousCollisionBol)
            {
                itemRect.moveTo(itemRect.x(), itemRect.y() + 1);
                isPreviousCollisionBol = false;
            }

            foreach (TopDesktopItemAbs *layoutedItem, layoutedItemsLst) {
                layoutedItemRowColPoint = posStr2Point(layoutedItem->config("position").toString());
                if (layoutedItemRowColPoint.x() > itemRect.y()
                        || (layoutedItemRowColPoint.x() == itemRect.y() && layoutedItemRowColPoint.y() >= itemRect.x()))
                {
                    layoutedItemRowColPoint.setX(layoutedItemRowColPoint.x() + 1);
                    layoutedItem->setConfig("position", point2PosStr(layoutedItemRowColPoint));
                }
            }
        }

        item->setConfig("position", point2PosStr(QPoint(itemRect.y(), itemRect.x())));
        item->blockSignals(false);
        layoutedItemsLst.push_back(item);
    }

    // 4. 放置
    int itemColSpan = 0;
    int itemRowSpan = 0;
    foreach (TopDesktopItemAbs *item, layoutedItemsLst) {
        itemRowColPoint = posStr2Point(item->config("position").toString());
        itemColSpan = item->colSpan();
        itemRowSpan = item->rowSpan();
        item->setFixedSize(cellWidthInt * itemColSpan + d->mGridLayout->spacing() * (itemColSpan - 1),
                           cellHeightInt * itemRowSpan + d->mGridLayout->spacing() * (itemRowSpan - 1));
        item->setMargin(3);
        item->doLayout();
        item->setHidden(!item->property("VISIBLE").toBool());
        d->mGridLayout->addWidget(item, itemRowColPoint.x(), itemRowColPoint.y(), itemRowSpan, itemColSpan, Qt::AlignLeft | Qt::AlignTop );
    }

    for (int i = 0; i < rowSpanInt - 1; ++i)
    {
        d->mGridLayout->setRowMinimumHeight(i, cellHeightInt);

        if (d->mGridLayout->itemAtPosition(i, 0) == 0)
        {
            d->mGridLayout->addItem(new QSpacerItem(cellWidthInt, cellHeightInt), i, 0, 1, 1);
        }
    }

    d->mGridLayout->setRowStretch(rowSpanInt - 1, 1);
    d->mGridLayout->setRowStretch(rowSpanInt, 1);

    for (int i = 0; i < colSpanInt - 1; ++i)
    {
        d->mGridLayout->setColumnMinimumWidth(i, cellWidthInt);
        if (d->mGridLayout->itemAtPosition(0, i))
        {
            d->mGridLayout->addItem(new QSpacerItem(cellWidthInt, cellHeightInt), 0, i, 1, 1);
        }
    }
    d->mGridLayout->setColumnStretch(colSpanInt - 1, 1);

    d->mGridLayout->setSizeConstraint(QLayout::SetMinimumSize);
    adjustSize();
    d->mItemsLst = itemOrder(d->mItemPrivority, d->mItemsLst);
    // 5. 设置stylesheet
    updateStyleSheet();
}

void TopWin8DesktopGroup::setModuleRight(const QMap<QString, QString> &iModuleRightMap)
{
    Q_D(TopWin8DesktopGroup);
    d->mModuleRightMap = iModuleRightMap;
}

QList<TopDesktopItemAbs *> TopWin8DesktopGroup::desktopItems(Qt::Orientation iPriorityOrder)
{
    Q_D(TopWin8DesktopGroup);

    if (iPriorityOrder != d->mItemPrivority)
    {
        d->mItemsLst = itemOrder(iPriorityOrder, d->mItemsLst);
    }
    return d->mItemsLst;
}

void TopWin8DesktopGroup::setColorList(TComboBox *iBackgroundCombox)
{
    QString colorsStr =  "["
                         "\"transparent\","
                         "\"rgba(0, 0, 0, 0.9)\","
                         "\"rgba(255, 255, 255, 0.9)\","
                         "\"rgba(42, 105, 238, 0.9)\","
                         "\"rgba(239, 59, 5, 0.9)\","
                         "\"rgba(255, 153, 0, 0.9)\","
                         "\"rgba(27, 117, 27, 0.9)\","
                         "\"rgba(110, 9, 189, 0.9)\","
                         "\"rgba(0, 204, 204, 0.9)\","
                         "\"rgba(51, 153, 51, 0.9)\","
                         "\"rgba(250, 123, 56, 0.9)\","
                         "\"rgba(86, 97, 153, 0.9)\","
                         "\"rgba(173, 86, 94, 0.9)\","
                         "\"rgba(128,128,255,0.9)\","
                         "\"rgba(164,99,255,0.9)\","
                         "\"rgba(0,128,128,0.9)\","
                         "\"rgba(204,51,51,0.9)\","
                         "\"rgba(255, 191, 24, 0.9)\""
                         "]";
    QVariantList btnBkgColorVarLst = TDataParse::jsonStr2Variant(colorsStr).toList();
    //1. 下拉框添加颜色字符
    QVariantList colorVarLst;
    foreach(QVariant itemVar, btnBkgColorVarLst)
    {
        QString colorStr = itemVar.toString();

        QVariantMap comboVarMap;
        comboVarMap.insert("name", colorStr);
        comboVarMap.insert("text", colorStr);

        colorVarLst << comboVarMap;
    }
    iBackgroundCombox->setItemList(colorVarLst);

    //2. 设置颜色图标
    for(int n = 0; n < colorVarLst.count(); n++)
    {
        QVariantMap itemVarMap = colorVarLst.at(n).toMap();
        QString colorStr = itemVarMap.value("text").toString();

        int rInt = 0, gInt = 0, bInt = 0;
        QRegExp rx("(\\d+)\\s*\\,\\s*(\\d+)\\s*\\,\\s*(\\d+)");
        if (rx.indexIn(colorStr) != -1)
        {
            rInt = rx.cap(1).toInt();
            gInt = rx.cap(2).toInt();
            bInt = rx.cap(3).toInt();
        }

        //创建pixmap
        const int widthInt = 80;
        const int heightInt = 20;
        QPixmap pixColor(widthInt, heightInt);
        pixColor.fill(QColor(rInt, gInt, bInt, 210));

        iBackgroundCombox->setItemIcon(n, QIcon(pixColor));
        iBackgroundCombox->setIconSize(QSize(widthInt, heightInt));
    }
}

void TopWin8DesktopGroup::setTitleColorList(TComboBox *iTitleCombox)
{
    QString colorsStr =  "["
                         "\"rgba(0, 0, 0, 0.9)\","
                         "\"rgba(255, 255, 255, 0.9)\""
                         "]";
    QVariantList btnBkgColorVarLst = TDataParse::jsonStr2Variant(colorsStr).toList();
    //1. 下拉框添加颜色字符
    QVariantList colorVarLst;
    foreach(QVariant itemVar, btnBkgColorVarLst)
    {
        QString colorStr = itemVar.toString();

        QVariantMap comboVarMap;
        comboVarMap.insert("name", colorStr);
        comboVarMap.insert("text", colorStr);

        colorVarLst << comboVarMap;
    }
    iTitleCombox->setItemList(colorVarLst);

    //2. 设置颜色图标
    for(int n = 0; n < colorVarLst.count(); n++)
    {
        QVariantMap itemVarMap = colorVarLst.at(n).toMap();
        QString colorStr = itemVarMap.value("text").toString();

        int rInt = 0, gInt = 0, bInt = 0;
        QRegExp rx("(\\d+)\\s*\\,\\s*(\\d+)\\s*\\,\\s*(\\d+)");
        if (rx.indexIn(colorStr) != -1)
        {
            rInt = rx.cap(1).toInt();
            gInt = rx.cap(2).toInt();
            bInt = rx.cap(3).toInt();
        }

        //创建pixmap
        const int widthInt = 80;
        const int heightInt = 20;
        QPixmap pixColor(widthInt, heightInt);
        pixColor.fill(QColor(rInt, gInt, bInt, 210));

        iTitleCombox->setItemIcon(n, QIcon(pixColor));
        iTitleCombox->setIconSize(QSize(widthInt, heightInt));
    }
}

void TopWin8DesktopGroup::showDockSequence(QFormLayout *iLayout, QSpinBox *iObj, bool iShowBol)
{
    iLayout->labelForField(iObj)->setHidden(!iShowBol);
    iObj->setHidden(!iShowBol);
}

void TopWin8DesktopGroup::setLabelAdjustSize(QLabel *label)
{
    label->adjustSize();
    label->setFixedWidth(20);
    label->setWordWrap(true);
    label->setAlignment(Qt::AlignCenter);
}

TopDesktopItemAbs::State TopWin8DesktopGroup::state() const
{
    Q_D(const TopWin8DesktopGroup);
    return d->state;
}

void TopWin8DesktopGroup::setState(TopDesktopItemAbs::State iState)
{
    Q_D(TopWin8DesktopGroup);
    d->state = iState;
    foreach (TopDesktopItemAbs *item, d->mItemsLst) {
        item->setState(iState);
    }
}

void TopWin8DesktopGroup::setModuleClickType(TopDesktopItemAbs::ClickType iClickType)
{
    Q_D(TopWin8DesktopGroup);
    d->clickType = iClickType;
    foreach (TopDesktopItemAbs *item, d->mItemsLst) {
        item->setClickType(iClickType);
    }
}

TopDesktopItemAbs::ClickType TopWin8DesktopGroup::moduleClickType() const
{
    Q_D(const TopWin8DesktopGroup);
    return d->clickType;
}

void TopWin8DesktopGroup::setConfigData(const QVariantMap &iConfigDataVarMap)
{
    Q_D(TopWin8DesktopGroup);

    d->mConfigDataVarMap = iConfigDataVarMap;

    QString titleStr = iConfigDataVarMap.value(QString("title_%1").arg(APP->language())).toString();
    if (titleStr.isEmpty()) titleStr = iConfigDataVarMap.value("title").toString();
    this->setTitle(titleStr);

    if (iConfigDataVarMap.contains("items"))
    {
        d->mItemsLst = createItems(iConfigDataVarMap.value("items").toList());
    }
    emit configChanged();
}

QVariantMap TopWin8DesktopGroup::configData()
{
    Q_D(TopWin8DesktopGroup);

    QVariantList itemsVarLst;
    foreach (TopDesktopItemAbs *dskItem, d->mItemsLst) {
        // 返回数据删除不需要的字段
        QVariantMap itemDataVarMap = dskItem->configData();
        itemDataVarMap.remove("uuid");
        itemsVarLst.push_back(dskItem->configData());
    }
    QVariantMap dataVarMap = d->mConfigDataVarMap;
    dataVarMap.insert("size", rowColStr2SizeStr(QString::number(rowSpan()), QString::number(colSpan())));
    dataVarMap.insert("items", itemsVarLst);
    return dataVarMap;
}

void TopWin8DesktopGroup::setConfig(const QString &iKeyStr, const QVariant &iValueVar)
{
    Q_D(TopWin8DesktopGroup);
    d->mConfigDataVarMap.insert(iKeyStr, iValueVar);
    dataChanged();
}

QVariant TopWin8DesktopGroup::config(const QString &iKeyStr) const
{
    Q_D(const TopWin8DesktopGroup);
    return d->mConfigDataVarMap.value(iKeyStr);
}

QPoint TopWin8DesktopGroup::position()
{
    return posStr2Point(config("position").toString());
}

void TopWin8DesktopGroup::setPosition(QPoint iPoint)
{
    setConfig("position", point2PosStr(iPoint));
}
void TopWin8DesktopGroup::setRowSpan(int iRowSpanInt)
{
    setConfig("rowSpan", iRowSpanInt);
}

int TopWin8DesktopGroup::rowSpan() const
{
    return config("rowSpan").toInt();
}

void TopWin8DesktopGroup::setColSpan(int iColSpanInt)
{
    setConfig("colSpan", iColSpanInt);
}

int TopWin8DesktopGroup::colSpan() const
{
    return config("colSpan").toInt();
}

void TopWin8DesktopGroup::setCellWidth(int iCellWidthInt)
{
    setConfig("cellWidth", iCellWidthInt);
}

int TopWin8DesktopGroup::cellWidth() const
{
    return config("cellWidth").toInt();
}

void TopWin8DesktopGroup::setCellHeight(int iCellHeight)
{
    setConfig("cellHeight", iCellHeight);
}

int TopWin8DesktopGroup::cellHeight() const
{
    return config("cellHeight").toInt();
}

QString TopWin8DesktopGroup::dockArea()
{
    return config("dockArea").toString();
}

void TopWin8DesktopGroup::setDockArea(const QString &iDockAreaStr)
{
    setConfig("dockArea", iDockAreaStr);
}

int TopWin8DesktopGroup::dockSequence()
{
    return config("dockSequence").toInt();
}

void TopWin8DesktopGroup::setDockSequence(int iSequenceInt)
{
    setConfig("dockSequence", iSequenceInt);
}

bool TopWin8DesktopGroup::removeOne(TopDesktopItemAbs *iDesktopItem)
{
    Q_D(TopWin8DesktopGroup);
    return d->mItemsLst.removeOne(iDesktopItem);
}

void TopWin8DesktopGroup::appendOne(TopDesktopItemAbs *iDesktopItem)
{
    Q_D(TopWin8DesktopGroup);
    if (iDesktopItem) d->mItemsLst.prepend(iDesktopItem);
}

void TopWin8DesktopGroup::clear()
{
    Q_D(TopWin8DesktopGroup);
    foreach (TopDesktopItemAbs *item, d->mItemsLst) {
        delete item;
    }
    d->mItemsLst.clear();
}

QPoint TopWin8DesktopGroup::posStr2Point(const QString &iPosStr)
{
    QString posRegStr("[0-9]{1,20},[0-9]{1,20}");
    QRegExp rx(posRegStr);

    if (!rx.exactMatch(iPosStr)) return QPoint(0, 0);

    QString posStr = iPosStr;
    QStringList posStrLst = posStr.split(',');
    return QPoint(posStrLst.at(0).toInt(), posStrLst.at(1).toInt());
}

QString TopWin8DesktopGroup::point2PosStr(QPoint iPoint)
{
    return QString("%1,%2").arg(iPoint.x()).arg(iPoint.y());
}

QSize TopWin8DesktopGroup::sizeStr2QSize(const QString &iSizeStr)
{
    QString rowStr;
    QString colStr;
    QString sizeStr = iSizeStr;
    if (sizeStr.contains('x'))
    {
        QStringList sizeStrLst = sizeStr.split('x');
        rowStr = sizeStrLst.at(0);
        colStr = sizeStrLst.at(1);
    }
    if (rowStr.isEmpty()) rowStr = "0";
    if (colStr.isEmpty()) colStr = "0";

    QSize size(rowStr.toInt(), colStr.toInt());
    return size;
}

QString TopWin8DesktopGroup::rowColStr2SizeStr(const QString &iRowStr, const QString &iColStr)
{
    return QString("%1x%2").arg(iRowStr).arg(iColStr);
}

bool TopWin8DesktopGroup::showConfigDialog(bool iIsNewBol)
{
    TUiloaderDialog dialog;
    QString uimStr = TFileIo::readFileString(":/topclass/topdesktop/GroupInfo.ui.js");

    QString dockAreaStr = dockArea();
    int sequenceStr = dockSequence();
    int colSpanInt = colSpan();
    int rowSpanInt = rowSpan();
    QString itemTextStr = config("title_" + APP->language()).toString();
    if (itemTextStr.isEmpty())
    {
        itemTextStr = config("title").toString();
    }

    if (!iIsNewBol)
    {
        dialog.setTitle(tr("Edit - %1").arg(itemTextStr));
        dialog.setIcon("setting2.white");
    }
    else
    {
        dialog.setTitle(tr("New Group"));
        dialog.setIcon("add.white");
    }
    dialog.setSelf(this);
    dialog.setScriptEngine(APP->scriptEngine());
    dialog.resize(700, 600);
    dialog.setUiStr(uimStr);

    if (iIsNewBol) {
        this->setDockArea("top");
        this->setConfig("background", "transparent");
        this->setRowSpan(6);
        this->setColSpan(4);
    }
    QVariantMap dataVarMap = this->configData();
    dialog.loadValues(dataVarMap);
    QVariantMap retVarMap = dialog.run(true);
    dialog.close();
    if (retVarMap.isEmpty()) return false;
    setConfigData(retVarMap);
    updateStyleSheet();
    if (dockArea() != dockAreaStr || sequenceStr != dockSequence()
            || colSpan() != colSpanInt || rowSpanInt != rowSpan())
    {
        emit layoutedRequest();
    }
    return true;
}

void TopWin8DesktopGroup::deleteGroup()
{
    if (TMessageBox::msgbox(this,
                            tr("Are you sure to delete category group %1?").arg(this->title()),
                            "",
                            "Question",
                            tr("Delete"),
                            QStringList() << tr("Yes") + ":Yes:Accept" << tr("No") + ":No:Reject",
                            "No") == "Yes")
    {
        emit groupDeleted(this);
    }
}

void TopWin8DesktopGroup::addModuleItem()
{
    Q_D(TopWin8DesktopGroup);

    TopDesktopItemAbs *win8item = createDesktopItem();
    if (win8item->showConfigDialog())
    {
        QPoint clickPosition = mapClassPos2WidgetPos(d->mGroupMenu->property("POSITION").toPoint());

        win8item->setStartRow(rowAtWidget(clickPosition));
        win8item->setStartCol(colAtWidget(clickPosition));

        win8item->setConfig("position", point2PosStr(QPoint(rowAtWidget(clickPosition), colAtWidget(clickPosition))));
        d->mItemsLst.append(win8item);
        this->doLayout();
    }
    else
    {
        delete win8item;
    }
}

QString TopWin8DesktopGroup::ttr(const QString &iStr)
{
    return TopWin8DesktopGroupPrivate::i18NMap.value(iStr, iStr);
}

TopDesktopItemAbs *TopWin8DesktopGroup::createDesktopItem(const QVariant &iParsVar)
{
    QVariantMap itemVarMap = iParsVar.toMap();
    TopDesktopItemAbs *deskitem = new TopWin8DesktopItem();
    deskitem->setParent(this);
    deskitem->setState(this->state());
    deskitem->setClickType(this->moduleClickType());
    deskitem->setConfigData(itemVarMap);
    deskitem->setProperty("MODULE", this->property("MODULE").toString());
    // 根据url->moduleName->right
    bool hasRightBol = hasOpenItemRight(deskitem->urlAddress());
    deskitem->setHasOpenRight(hasRightBol);
    deskitem->setProperty("VISIBLE", hasRightBol);
    deskitem->doLayout();
    connect(deskitem, SIGNAL(clicked(QString, QVariant)), this, SIGNAL(urlRequested(QString, QVariant)));
    connect(deskitem, SIGNAL(doubleClicked(QString, QVariant)), this, SIGNAL(urlRequested(QString, QVariant)));
    connect(deskitem, SIGNAL(configChanged()), this, SLOT(dataChanged()));
    connect(deskitem, SIGNAL(layoutDone()), this, SLOT(doLayout()));
    connect(deskitem, SIGNAL(itemDeleted(TopDesktopItemAbs*)), this, SLOT(deleteItem(TopDesktopItemAbs*)));
    connect(deskitem, SIGNAL(itemTryDeleted(TopDesktopItemAbs*)), this, SLOT(tryDeleteItem(TopDesktopItemAbs*)));
    return deskitem;
}

QMenu *TopWin8DesktopGroup::createContextMenu()
{
    Q_D(TopWin8DesktopGroup);
    // 分组Menu
    if (!d->mGroupMenu)
    {
        QMenu *mGroupMenu = new QMenu(this);
        mGroupMenu->addAction(TRES->icon(""), tr("Setting Group"), this, SLOT(showConfigDialog()));
        mGroupMenu->addAction(TRES->icon(""), tr("Delete Group"), this, SLOT(deleteGroup()));
        mGroupMenu->addAction(TRES->icon(""), tr("Add Module"), this, SLOT(addModuleItem()));
        return mGroupMenu;
    }
    return d->mGroupMenu;
}

void TopWin8DesktopGroup::deleteItem(TopDesktopItemAbs *iItem)
{
    Q_D(TopWin8DesktopGroup);
    if (iItem)
    {
        if (d->mItemsLst.removeOne(iItem)) iItem->deleteLater();
        else iItem->close();
        dataChanged();
    }
}

void TopWin8DesktopGroup::tryDeleteItem(TopDesktopItemAbs *iItem)
{
    Q_D(TopWin8DesktopGroup);
    d->mItemsLst.removeOne(iItem);
}

void TopWin8DesktopGroup::dataChanged()
{
    emit configChanged();
}

void TopWin8DesktopGroup::mousePressEvent(QMouseEvent *iEvent)
{
    Q_D(TopWin8DesktopGroup);
    if (state() == TopDesktopItemAbs::State_Editing && iEvent->button() == Qt::LeftButton)
    {
        d->startDragBol = true;
        d->pressPos = iEvent->pos();
    }
}

void TopWin8DesktopGroup::mouseReleaseEvent(QMouseEvent *iEvent)
{
    Q_D(TopWin8DesktopGroup);
    if (iEvent->button() == Qt::RightButton)
    {
        if (d->state == TopDesktopItemAbs::State_Editing)
        {
            if (d->mGroupMenu == NULL)
            {
                d->mGroupMenu = createContextMenu();
            }
            d->mGroupMenu->setProperty("POSITION", iEvent->pos());
            d->mGroupMenu->popup(QCursor::pos());
        }
    }
    d->startDragBol = false;
    d->drawCurPosiRectBol = false;
}

void TopWin8DesktopGroup::mouseMoveEvent(QMouseEvent *iEvent)
{
    Q_D(TopWin8DesktopGroup);
    if (d->startDragBol && (qAbs(iEvent->pos().x() - d->pressPos.x()) > 7
                            || qAbs(iEvent->pos().y() - d->pressPos.y()) > 7))
    {
        QByteArray groupBytLst;
        QDataStream dataStream(&groupBytLst, QIODevice::WriteOnly);

        dataStream << QPoint(iEvent->pos())
                   << this->title()
                   << this->size()
                   << QSize(cellWidth(), cellHeight())
                   << TDataParse::variant2JsonStr(this->configData());

        QMimeData *mimeData = new QMimeData;
        mimeData->setData("application/desktop-groupdata", groupBytLst);

        QPixmap pixmap(this->size());
        this->render(&pixmap);

        QDrag *drag = new QDrag(this);
        drag->setMimeData(mimeData);
        drag->setPixmap(pixmap);

        QPoint point(iEvent->pos());
        drag->setHotSpot(point);

        this->setAttribute(Qt::WA_DeleteOnClose);

        Qt::DropAction dropAction = drag->exec(Qt::MoveAction | Qt::CopyAction, Qt::CopyAction);
        if (dropAction == Qt::MoveAction)
        {
            this->close();
        }
    }
}

void TopWin8DesktopGroup::dragMoveEvent(QDragMoveEvent *iEvent)
{
    if (iEvent->mimeData()->hasFormat("application/desktop-itemdata") && !isCollisionLayoutedItems(iEvent))
    {
        if (QString(iEvent->source()->property("MODULE").toString())
                == QString(this->property("MODULE").toString()))
        {
            iEvent->setDropAction(Qt::MoveAction);
            iEvent->accept();
        }
        else
        {
            iEvent->acceptProposedAction();
        }
    }
    else
    {
        iEvent->ignore();
    }
}

void TopWin8DesktopGroup::dragEnterEvent(QDragEnterEvent *iEvent)
{
    if (iEvent->mimeData()->hasFormat("application/desktop-itemdata"))
    {
        if (QString(iEvent->source()->property("MODULE").toString())
                == QString(this->property("MODULE").toString()))
        {
            iEvent->setDropAction(Qt::MoveAction);
            iEvent->accept();
        }
        else
        {
            iEvent->acceptProposedAction();
        }
    }
    else
    {
        iEvent->ignore();
    }
}

void TopWin8DesktopGroup::dropEvent(QDropEvent *iEvent)
{
    Q_D(TopWin8DesktopGroup);

    d->drawCurPosiRectBol = false;
    if (iEvent->mimeData()->hasFormat("application/desktop-itemdata") && !isCollisionLayoutedItems(iEvent)) {
        QByteArray itemDataBytLst = iEvent->mimeData()->data("application/desktop-itemdata");
        QDataStream dataStream(&itemDataBytLst, QIODevice::ReadOnly);

        QPoint offsetPoint;
        QString itemDataStr;
        bool hasOpenrightBol = false;
        QSize itemSize;

        dataStream >> offsetPoint >> itemSize >> hasOpenrightBol >> itemDataStr;
        TopDesktopItemAbs *newItem = createDesktopItem(TDataParse::jsonStr2Variant(itemDataStr));
        if (!newItem) return;
        newItem->setHasOpenRight(hasOpenrightBol);
        newItem->move(iEvent->pos() - offsetPoint);

        newItem->setAttribute(Qt::WA_DeleteOnClose);

        d->mItemsLst.removeOne(qobject_cast<TopDesktopItemAbs *>(iEvent->source()));
        iEvent->setDropAction(Qt::MoveAction);
        iEvent->accept();

        // 根据放下的位置计算item应该在的位置,将item加入到mItemLst中
        QPoint movePosi = mapClassPos2WidgetPos(iEvent->pos()) - offsetPoint;
        QPoint centerPosi = QPoint(movePosi.x() + itemSize.width() / 2, movePosi.y() + itemSize.height() / 2) ;

        QPoint calcPosi = movePosi;

        if (newItem->colSpan() == 1 && newItem->rowSpan() == 1)
        {
            calcPosi = centerPosi;
        }
        else
        {
            calcPosi = movePosi + QPoint(WndSize_ItemCalcSpace, WndSize_ItemCalcSpace);
        }

        insertItem(calcPosi, newItem);
    }
    else
    {
        iEvent->ignore();
    }
}

void TopWin8DesktopGroup::paintEvent(QPaintEvent *iEvent)
{
    Q_D(TopWin8DesktopGroup);
    if (d->drawCurPosiRectBol && state() == TopDesktopItemAbs::State_Editing)
    {
        QPainter painter(this);
        QColor color(QColor(TTHEME->value("TITLE").toString()));
        QBrush brush(color);
        QPen pen(brush, 2, Qt::DashDotLine, Qt::RoundCap, Qt::RoundJoin);
        painter.setPen(pen);
    }
    QGroupBox::paintEvent(iEvent);
}

void TopWin8DesktopGroup::mouseDoubleClickEvent(QMouseEvent *iEvent)
{
    if (iEvent->button() == Qt::LeftButton && state() == TopDesktopItemAbs::State_Editing)
    {
        showConfigDialog();
    }
    QGroupBox::mouseDoubleClickEvent(iEvent);
}

QList<TopDesktopItemAbs *> TopWin8DesktopGroup::createItems(const QVariantList &iItemsVarLst)
{
    QList<TopDesktopItemAbs *> mItemsLst;
    foreach (QVariant itemVar, iItemsVarLst) {
        mItemsLst.push_back(createDesktopItem(itemVar));
    }

    return mItemsLst;
}

// 说明:  mapClassPos2WidgetPos
// 参数:  iPoint: QPoint 是相对于Class的点位置
// 返回值 :是相对于CenterWidget的位置
//   见:布局框架
//        - mScrollArea.pos()   目的是算出Class Event 发出的点Point在mScrollArea中位置
//   同理 -mCenterWidget->pos() 目的是算出在mscrollArea中位置 在 CenterWidget中的位置
QPoint TopWin8DesktopGroup::mapClassPos2WidgetPos(QPoint iPoint)
{
    Q_D(TopWin8DesktopGroup);
    return iPoint - d->mScrollArea->pos() - d->mCenterWidget->pos();
}

int TopWin8DesktopGroup::rowAtWidget(QPoint iAtWidgetPoint)
{
    Q_D(TopWin8DesktopGroup);
    int atRowInt = 0;
    for (int rowInt = 0; ; ++rowInt) {
        int yInt = 0;
        if (rowInt > 0)
        {
            yInt = cellHeight() * rowInt + d->mGridLayout->spacing() * rowInt + d->mGridLayout->margin();
        }
        else
        {
            yInt = cellHeight() * rowInt + d->mGridLayout->margin();
        }

        if (yInt < iAtWidgetPoint.y())
        {
            atRowInt = rowInt;
        }
        else
        {
            break;
        }
    }
    return atRowInt;
}

int TopWin8DesktopGroup::colAtWidget(QPoint iAtWidgetPoint)
{
    Q_D(TopWin8DesktopGroup);
    int atColInt = 0;
    for (int colInt = 0; ; ++colInt)
    {
        int xInt = 0;
        if (colInt > 0)
        {
            xInt = cellWidth() * colInt + d->mGridLayout->spacing() * colInt + d->mGridLayout->margin();
        }
        else
        {
            xInt = cellWidth() * colInt + d->mGridLayout->margin();
        }

        if (xInt < iAtWidgetPoint.x())
        {
            atColInt = colInt;
        }
        else
        {
            break;
        }
    }
    return atColInt;
}

void TopWin8DesktopGroup::insertItem(QPoint iDropPoint, TopDesktopItemAbs *iInsetedItem)
{
    Q_D(TopWin8DesktopGroup);
    // 放下点的行
    int rowInt = rowAtWidget(iDropPoint);
    int colInt = colAtWidget(iDropPoint);

    // 放下的行列
    d->mItemsLst.append(iInsetedItem);
    iInsetedItem->setConfig("position", point2PosStr(QPoint(rowInt, colInt)));

    doLayout();
}

bool TopWin8DesktopGroup::isBeyondPlacedArea(QRect iRect, int iPlacedWidthInt)
{
    return (iRect.x() + iRect.width() > iPlacedWidthInt) ? true : false;
}

bool TopWin8DesktopGroup::isCollisionWithLayoutedItems(QRect iRect,
                                                       const QList<TopDesktopItemAbs *> iLayoutedItemsLst,
                                                       bool *oIsPreviousCollisionBol)
{
    QRect  layoutedItemRect;
    QPoint layoutedItemPoint;

    foreach (TopDesktopItemAbs *item, iLayoutedItemsLst) {
        layoutedItemPoint = posStr2Point(item->config("position").toString());
        layoutedItemRect  = QRect(QPoint(layoutedItemPoint.y(), layoutedItemPoint.x()),
                                  QSize(item->colSpan(), item->rowSpan()));
        if (layoutedItemRect.intersects(iRect))
        {
            if (oIsPreviousCollisionBol)
            {
                if (layoutedItemRect.y() < iRect.y()
                        || (layoutedItemRect.y() == iRect.y()
                            && layoutedItemRect.x() < iRect.x()))
                {
                    *oIsPreviousCollisionBol = true;
                }
                else
                {
                    *oIsPreviousCollisionBol = false;
                }
            }
            return true;
        }
    }
    return false;
}

bool TopWin8DesktopGroup::isCollisionLayoutedItems(QDropEvent *iEvent)
{
    Q_D(TopWin8DesktopGroup);

    QByteArray itemDataBytLst = iEvent->mimeData()->data("application/desktop-itemdata");
    QDataStream dataStream(&itemDataBytLst, QIODevice::ReadOnly);

    QPoint offsetPoint;
    QString itemDataStr;
    bool hasOpenrightBol = false;
    QSize itemSize;
    dataStream >> offsetPoint >> itemSize >> hasOpenrightBol >> itemDataStr;
    TopDesktopItemAbs *newItem = createDesktopItem(TDataParse::jsonStr2Variant(itemDataStr));


    QPoint movePosition = mapClassPos2WidgetPos(iEvent->pos()) - offsetPoint;
    QPoint centerPosi = QPoint(movePosition.x() + itemSize.width() / 2, movePosition.y() + itemSize.height() / 2) ;
    QPoint calcPosi;

    if (newItem->colSpan() == 1 && newItem->rowSpan() == 1)
    {
        calcPosi = centerPosi;
    }
    else
    {
        calcPosi = movePosition + QPoint(WndSize_ItemCalcSpace, WndSize_ItemCalcSpace);
    }

    QRect rect = QRect(QPoint(colAtWidget(calcPosi), rowAtWidget(calcPosi)),
                       QSize(newItem->colSpan(),
                             newItem->rowSpan()));

    delete newItem;
    return isCollisionWithLayoutedItems(rect, d->mItemsLst);
}

void TopWin8DesktopGroup::updateStyleSheet()
{
    Q_D(TopWin8DesktopGroup);
    QString background = config("background").toString();
    if (background != d->defaultBackground) {
        d->mScrollArea->setStyleSheet(QString(".TScrollArea{background:transparent; border-width:0px;}"
                                              ".QWidget#CENTERWIDGET{background:%1;}")
                                      .arg(config("background").toString()));
    }
    QString titleColor = config("titleColor").toString();
    if (titleColor != d->defaultTitleColor) {
        this->setStyleSheet(QString("QGroupBox[SS=\"DESKTOPGROUP\"]{border:none;font-size:18px;margin-top: 24px;} "
                                    "QGroupBox[SS=\"DESKTOPGROUP\"]::title { subcontrol-origin: margin;subcontrol-position:top left;padding-left: 5px;color:%1;}")
                            .arg(config("titleColor").toString()));
    }
}

bool TopWin8DesktopGroup::hasOpenItemRight(const QString &iUrlStr)
{
    Q_D(TopWin8DesktopGroup);
    QVariantMap dataMap = TDataParse::commandStr2Map(iUrlStr);
    QString moduleNameStr = dataMap.value("COM").toString().toUpper();

    if (d->mModuleRightMap.contains(moduleNameStr))
    {
        return APP->hasRight(d->mModuleRightMap.value(moduleNameStr));
    }
    return true;
}

QList<TopDesktopItemAbs *> TopWin8DesktopGroup::itemOrder(Qt::Orientation iPriorityOrder, const QList<TopDesktopItemAbs *>& iItemLst)
{
    QList<TopDesktopItemAbs *> itemLst = iItemLst;
    if (iItemLst.isEmpty()) return itemLst;

    QMap<const TopDesktopItemAbs *, int> rowItemMap;
    QMap<const TopDesktopItemAbs *, int> colItemMap;
    foreach (TopDesktopItemAbs *item, iItemLst) {
        QString relativePosStr = item->config("position").toString().trimmed();
        QPoint relativePos = posStr2Point(relativePosStr.isEmpty() ? QString("0,0") : relativePosStr);
        rowItemMap.insert(item,  relativePos.x());
        colItemMap.insert(item, relativePos.y());
    }


    if (iPriorityOrder == Qt::Horizontal)
    {
        qSort(itemLst.begin(), itemLst.end(), [=](const TopDesktopItemAbs*item1, const TopDesktopItemAbs*item2)
        {
            int y1 = rowItemMap.value(item1);
            int y2 = rowItemMap.value(item2);
            int x1 = colItemMap.value(item1);
            int x2 = colItemMap.value(item2);

            return y1 < y2 || (y1 == y2 && x1 < x2);
        });
    }
    else
    {
        qSort(itemLst.begin(), itemLst.end(), [=](const TopDesktopItemAbs*item1, const TopDesktopItemAbs*item2)
        {
            int y1 = rowItemMap.value(item1);
            int y2 = rowItemMap.value(item2);
            int x1 = colItemMap.value(item1);
            int x2 = colItemMap.value(item2);
            return x1 < x2 || (x1 == x2 && y1 < y2);
        });
    }
    return itemLst;
}