File indexing completed on 2024-12-22 04:14:59

0001 /*
0002  *  SPDX-FileCopyrightText: 2020 Saurabh Kumar <saurabhk660@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "StoryboardDelegate.h"
0008 #include "StoryboardModel.h"
0009 
0010 #include <QLineEdit>
0011 #include <QTextEdit>
0012 #include <QDebug>
0013 #include <QStyle>
0014 #include <QPainter>
0015 #include <QApplication>
0016 #include <QSize>
0017 #include <QMouseEvent>
0018 #include <QListView>
0019 #include <QSpinBox>
0020 #include <QScrollBar>
0021 
0022 #include <kis_icon.h>
0023 #include <kis_image_animation_interface.h>
0024 #include <commands_new/kis_switch_current_time_command.h>
0025 #include "KisAddRemoveStoryboardCommand.h"
0026 
0027 
0028 StoryboardDelegate::StoryboardDelegate(QObject *parent)
0029     : QStyledItemDelegate(parent)
0030     , m_view(nullptr)
0031     , m_imageSize(QSize())
0032 {
0033 }
0034 
0035 StoryboardDelegate::~StoryboardDelegate()
0036 {
0037 }
0038 
0039 void StoryboardDelegate::paint(QPainter *p, const QStyleOptionViewItem &option, const QModelIndex &index) const
0040 {
0041     p->save();
0042     {
0043         QStyle *style = option.widget ? option.widget->style() : QApplication::style();
0044         style->drawPrimitive(QStyle::PE_PanelItemViewItem, &option, p, option.widget);
0045 
0046         p->setFont(option.font);
0047         if (!index.isValid()) {
0048             p->restore();
0049             return;
0050         }
0051         if (!index.parent().isValid()) {
0052             QRect parentRect = option.rect;
0053             p->setPen(QPen(option.palette.window(), 2));
0054             p->drawRect(parentRect);
0055 
0056             parentRect.setTopLeft(parentRect.topLeft() + QPoint(4, 4));
0057             parentRect.setBottomRight(parentRect.bottomRight() - QPoint(4, 4));
0058 
0059             if (option.state & QStyle::State_Selected) {
0060                 p->fillRect(option.rect, option.palette.highlight());
0061             }
0062             else {
0063                 p->fillRect(option.rect, option.palette.window());
0064             }
0065             p->eraseRect(parentRect);
0066         }
0067         else {
0068             //draw the child items
0069             int childNum = index.row();
0070             QString data = index.data().toString();
0071 
0072             switch (childNum)
0073             {
0074             case StoryboardItem::FrameNumber:
0075             {
0076                 if (m_view->thumbnailIsVisible()) {
0077                     QRect frameNumRect = option.rect;
0078                     frameNumRect.setHeight(m_view->fontMetrics().height()+3);
0079 #if QT_VERSION >= QT_VERSION_CHECK(5,11,0)
0080                     frameNumRect.setWidth(3 * m_view->fontMetrics().horizontalAdvance("0") + 2);
0081 #else
0082                     frameNumRect.setWidth(3 * m_view->fontMetrics().width('0') + 2);
0083 #endif
0084                     frameNumRect.moveBottom(option.rect.top()-1);
0085                     p->setPen(QPen(option.palette.dark(), 2));
0086                     p->drawRect(frameNumRect);
0087                     p->setPen(QPen(option.palette.text(), 1));
0088                     p->drawText(frameNumRect, Qt::AlignHCenter | Qt::AlignVCenter, data);
0089 
0090                     if (!m_imageSize.isEmpty()) {
0091                         float scale = qMin(option.rect.height() / (float)m_imageSize.height(), (float)option.rect.width() / m_imageSize.width());
0092                         QRect thumbnailRect = option.rect;
0093                         thumbnailRect.setSize(m_imageSize * scale);
0094                         thumbnailRect.moveCenter(option.rect.center());
0095 
0096                         QPixmap  thumbnailPixmap= index.data(Qt::UserRole).value<QPixmap>();
0097                         p->drawPixmap(thumbnailRect, thumbnailPixmap);
0098                     }
0099                     p->setPen(QPen(option.palette.dark(), 2));
0100                     p->drawRect(option.rect);
0101 
0102                     QRect buttonsRect = option.rect;
0103                     buttonsRect.setTop(option.rect.bottom() - 22);
0104 
0105                     buttonsRect.setWidth(22);
0106                     buttonsRect.moveBottomLeft(option.rect.bottomLeft());
0107                     QIcon addIcon = KisIconUtils::loadIcon("list-add");
0108                     p->fillRect(buttonsRect, option.palette.window());
0109                     addIcon.paint(p, buttonsRect);
0110 
0111                     buttonsRect.moveBottomRight(option.rect.bottomRight());
0112                     QIcon deleteIcon = KisIconUtils::loadIcon("edit-delete");
0113                     p->fillRect(buttonsRect, option.palette.window());
0114                     deleteIcon.paint(p, buttonsRect);
0115                 }
0116                 else {
0117                     QRect frameNumRect = option.rect;
0118                     p->setPen(QPen(option.palette.dark(), 2));
0119                     p->drawRect(frameNumRect);
0120                     p->setPen(QPen(option.palette.text(), 1));
0121                     p->drawText(frameNumRect, Qt::AlignHCenter | Qt::AlignVCenter, data);
0122                 }
0123                 break;
0124             }
0125             case StoryboardItem::ItemName:
0126             {
0127                 QRect itemNameRect = option.rect;
0128                 itemNameRect.setLeft(option.rect.left() + 5);
0129                 p->setPen(QPen(option.palette.text(), 1));
0130                 p->drawText(itemNameRect, Qt::AlignLeft | Qt::AlignVCenter, data);
0131                 p->setPen(QPen(option.palette.dark(), 2));
0132                 p->drawRect(option.rect);
0133                 break;
0134             }
0135             case StoryboardItem::DurationSecond:
0136             {
0137                 drawSpinBox(p, option, data, i18nc("suffix in spin box in storyboard that means 'seconds'", "s"));
0138                 break;
0139             }
0140             case StoryboardItem::DurationFrame:
0141             {
0142                 drawSpinBox(p, option, data, i18nc("suffix in spin box in storyboard that means 'frames'", "f"));
0143                 break;
0144             }
0145             default:
0146             {
0147                 KIS_SAFE_ASSERT_RECOVER_RETURN(index.model());
0148                 const StoryboardModel* model = dynamic_cast<const StoryboardModel*>(index.model());
0149                 KIS_SAFE_ASSERT_RECOVER_RETURN(model);
0150                 if (m_view->commentIsVisible() && model->getComment(index.row() - 4).visibility) {
0151                     p->setPen(QPen(option.palette.dark(), 2));
0152                     drawCommentHeader(p, option, index);
0153                 }
0154                 break;
0155             }
0156             }
0157         }
0158     }
0159     p->restore();
0160 }
0161 
0162 void StoryboardDelegate::drawSpinBox(QPainter *p, const QStyleOptionViewItem &option, QString data, QString suffix) const
0163 {
0164     QStyle *style = option.widget ? option.widget->style() : QApplication::style();
0165     QStyleOptionSpinBox spinBoxOption;
0166     spinBoxOption.stepEnabled = QAbstractSpinBox::StepDownEnabled | QAbstractSpinBox::StepUpEnabled;
0167     spinBoxOption.subControls = QStyle::SC_SpinBoxUp | QStyle::SC_SpinBoxDown;
0168     spinBoxOption.rect = option.rect;
0169     p->setPen(QPen(option.palette.dark(), 2));
0170     p->drawRect(option.rect);
0171     style->drawComplexControl(QStyle::CC_SpinBox, &spinBoxOption, p, option.widget);
0172 
0173     QRect rect = style->subControlRect(QStyle::CC_SpinBox, &spinBoxOption,
0174                                        QStyle::QStyle::SC_SpinBoxEditField);
0175     rect.moveTopLeft(option.rect.topLeft());
0176     p->setPen(QPen(option.palette.text(), 1));
0177     p->drawText(rect, Qt::AlignLeft | Qt::AlignVCenter, data + suffix);
0178 }
0179 
0180 QStyleOptionSlider StoryboardDelegate::drawCommentHeader(QPainter *p, const QStyleOptionViewItem &option, const QModelIndex &index) const
0181 {
0182     QStyle *style = option.widget ? option.widget->style() : QApplication::style();
0183     KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(index.model(), QStyleOptionSlider());
0184     const StoryboardModel* model = dynamic_cast<const StoryboardModel*>(index.model());
0185     KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(model, QStyleOptionSlider());
0186     QString data = index.data().toString();
0187 
0188     QRect titleRect = option.rect;
0189     titleRect.setHeight(option.fontMetrics.height() + 3);
0190     if (p) {
0191         p->setPen(QPen(option.palette.text(), 1));
0192         p->drawText(titleRect, Qt::AlignLeft | Qt::AlignVCenter, model->getComment(index.row() - 4).name);
0193         p->setPen(QPen(option.palette.dark(), 2));
0194         p->drawRect(titleRect);
0195     }
0196 
0197     QRect contentRect = option.rect;
0198     contentRect.setTop(option.rect.top() + option.fontMetrics.height() + 3);
0199     if (p) {
0200         p->setPen(QPen(option.palette.dark(), 2));
0201         p->drawRect(contentRect);
0202         p->save();
0203     }
0204     contentRect.setTopLeft(contentRect.topLeft() + QPoint(5, 5));
0205     contentRect.setBottomRight(contentRect.bottomRight() - QPoint(5, 5));
0206 
0207     int scrollValue = index.data(Qt::UserRole).toInt();
0208 
0209     //draw comment
0210     QRect commentRect = contentRect;
0211     commentRect.setRight(contentRect.right() - 15);
0212     QTextDocument doc;
0213 
0214     doc.setTextWidth(commentRect.width());
0215     doc.setDocumentMargin(0);
0216     doc.setDefaultFont(option.font);
0217     QStringList lines = data.split('\n');
0218     QString HTML;
0219     Q_FOREACH( const QString& line, lines) {
0220         HTML.append("<p>" + line + "</p>");
0221     }
0222     doc.setHtml(HTML);
0223     QRectF clipRect = commentRect;
0224     clipRect.moveTopLeft(QPoint(0, 0 + scrollValue));
0225     if (p) {
0226         p->translate(QPoint(commentRect.topLeft().x(), commentRect.topLeft().y() - scrollValue));
0227         p->setPen(QPen(option.palette.text(), 1));
0228         doc.drawContents(p, clipRect);
0229         p->restore();
0230     }
0231     //draw scroll bar
0232     QStyleOptionSlider scrollbarOption;
0233     scrollbarOption.sliderPosition = scrollValue;
0234     scrollbarOption.minimum = 0;
0235     scrollbarOption.maximum = qMax(0.0, doc.size().height() - contentRect.height());
0236     scrollbarOption.sliderPosition = qMin(scrollValue, scrollbarOption.maximum);
0237     scrollbarOption.pageStep = contentRect.height() - 2;
0238     scrollbarOption.orientation = Qt::Vertical;
0239 
0240     QRect scrollRect = option.rect;
0241     scrollRect.setSize(QSize(15, option.rect.height() - option.fontMetrics.height() - 3));
0242     scrollRect.moveTopLeft(QPoint(0, 0));
0243     scrollbarOption.rect = scrollRect;
0244 
0245     if (p && scrollbarOption.pageStep <= doc.size().height()) {
0246         p->save();
0247         p->setPen(QPen(option.palette.dark(), 2));
0248         p->translate(QPoint( option.rect.right()-15, option.rect.top() + option.fontMetrics.height() + 3));
0249         style->drawComplexControl(QStyle::CC_ScrollBar, &scrollbarOption, p, option.widget);
0250         p->restore();
0251     }
0252     return scrollbarOption;
0253 }
0254 
0255 QSize StoryboardDelegate::sizeHint(const QStyleOptionViewItem &option,
0256                                    const QModelIndex &index) const
0257 {
0258     if (!index.parent().isValid()) {
0259         KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(index.model(), option.rect.size());
0260         if (m_view->itemOrientation() == Qt::Vertical) {
0261             int width = option.widget->width() - 17;
0262             const StoryboardModel* model = dynamic_cast<const StoryboardModel*>(index.model());
0263             KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(model, option.rect.size());
0264             int numComments = model->visibleCommentCount();
0265             int numItem = width/250;
0266             if (numItem <= 0) {
0267                 numItem = 1;
0268             }
0269 
0270             int thumbnailheight = m_view->thumbnailIsVisible() ? 120 : 0;
0271             int commentHeight = m_view->commentIsVisible() ? numComments*100 : 0;
0272             return QSize(width / numItem, thumbnailheight  + option.fontMetrics.height() + 3 + commentHeight + 10);
0273         }
0274         else {
0275             const StoryboardModel* model = dynamic_cast<const StoryboardModel*>(index.model());
0276             KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(model, option.rect.size());
0277             int numComments = model->visibleCommentCount();
0278             int commentWidth = 0;
0279             if (numComments && m_view->commentIsVisible()) {
0280                 commentWidth = qMax(200, (m_view->viewport()->width() - 250) / numComments);
0281             }
0282             int width = 250 + numComments * commentWidth;
0283             return QSize(width + 10, 120 + option.fontMetrics.height() + 3 + 10);
0284         }
0285     }
0286     else {
0287         return option.rect.size();
0288     }
0289 }
0290 
0291 QWidget *StoryboardDelegate::createEditor(QWidget *parent,
0292                                           const QStyleOptionViewItem &option ,
0293                                           const QModelIndex &index) const
0294 {
0295     Q_UNUSED(option);
0296     //only create editor for children
0297     if (index.parent().isValid()) {
0298         int row = index.row();
0299         switch (row)
0300         {
0301         case StoryboardItem::FrameNumber:
0302             return nullptr;
0303         case StoryboardItem::ItemName:
0304         {
0305             QLineEdit *editor = new QLineEdit(parent);
0306             return editor;
0307         }
0308         case StoryboardItem::DurationSecond:
0309         {
0310             QSpinBox *spinbox = new QSpinBox(parent);
0311             spinbox->setRange(0, 999);
0312             spinbox->setSuffix(i18nc("suffix in spin box in storyboard that means 'seconds'", "s"));
0313             return spinbox;
0314         }
0315         case StoryboardItem::DurationFrame:
0316         {
0317             QSpinBox *spinbox = new QSpinBox(parent);
0318             spinbox->setRange(0, 99);
0319             spinbox->setSuffix(i18nc("suffix in spin box in storyboard that means 'frames'", "f"));
0320             return spinbox;
0321         }
0322         default:              //for comments
0323         {
0324             QTextEdit *editor = new LimitedTextEditor(280, parent);
0325             return editor;
0326         }
0327         }
0328     }
0329     return nullptr;
0330 }
0331 
0332 bool StoryboardDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index)
0333 {
0334     KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(model, false);
0335     if ((event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseButtonDblClick)
0336             && (index.flags() & Qt::ItemIsEnabled))
0337     {
0338         QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
0339         const bool leftButton = mouseEvent->buttons() & Qt::LeftButton;
0340 
0341         //handle the duration edit event
0342         if (index.parent().isValid() && (index.row() == StoryboardItem::DurationSecond || index.row() == StoryboardItem::DurationFrame)) {
0343             QRect upButton = spinBoxUpButton(option);
0344             QRect downButton = spinBoxDownButton(option);
0345 
0346             bool upButtonClicked = upButton.isValid() && upButton.contains(mouseEvent->pos());
0347             bool downButtonClicked = downButton.isValid() && downButton.contains(mouseEvent->pos());
0348 
0349             StoryboardModel* sbModel = dynamic_cast<StoryboardModel*>(model);
0350             KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(sbModel, false);
0351             if (leftButton && upButtonClicked) {
0352                 KisStoryboardChildEditCommand *cmd = new KisStoryboardChildEditCommand(index.data(),
0353                                                                                     index.data().toInt() + 1,
0354                                                                                     index.parent().row(),
0355                                                                                     index.row(),
0356                                                                                     sbModel);
0357                 if (sbModel->setData(index, index.data().toInt() + 1)) {
0358                     sbModel->pushUndoCommand(cmd);
0359                 }
0360                 return true;
0361             }
0362             else if (leftButton && downButtonClicked) {
0363                 KisStoryboardChildEditCommand *cmd = new KisStoryboardChildEditCommand(index.data(),
0364                                                                                     index.data().toInt() - 1,
0365                                                                                     index.parent().row(),
0366                                                                                     index.row(),
0367                                                                                     sbModel);
0368                 if (sbModel->setData(index, index.data().toInt() - 1)) {
0369                     sbModel->pushUndoCommand(cmd);
0370                 }
0371                 return true;
0372             }
0373         }
0374         else if (index.parent().isValid() && index.row() >= StoryboardItem::Comments) {
0375             QStyleOptionSlider scrollBarOption = drawCommentHeader(nullptr, option, index);
0376             QRect upButton = scrollUpButton(option, scrollBarOption);
0377             QRect downButton = scrollDownButton(option, scrollBarOption);
0378 
0379             bool upButtonClicked = upButton.isValid() && upButton.contains(mouseEvent->pos());
0380             bool downButtonClicked = downButton.isValid() && downButton.contains(mouseEvent->pos());
0381 
0382             if (leftButton && upButtonClicked) {
0383                 int lastValue = model->data(index, Qt::UserRole).toInt();
0384                 int value = lastValue - option.fontMetrics.height();
0385                 StoryboardModel* modelSB = dynamic_cast<StoryboardModel*>(model);
0386                 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(modelSB, false);
0387                 modelSB->setCommentScrollData(index, qMax(0, value));
0388                 return true;
0389             }
0390             else if (leftButton && downButtonClicked) {
0391                 int lastValue = model->data(index, Qt::UserRole).toInt();
0392                 int value = lastValue + option.fontMetrics.height();
0393                 StoryboardModel* modelSB = dynamic_cast<StoryboardModel*>(model);
0394                 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(modelSB, false);
0395                 modelSB->setCommentScrollData(index, qMin(scrollBarOption.maximum, value));
0396                 return true;
0397             }
0398         }
0399 
0400         else if (index.parent().isValid() && index.row() == StoryboardItem::FrameNumber && m_view->thumbnailIsVisible()) {     //thumbnail add/delete events
0401             QRect addItemButton(QPoint(0, 0), QSize(22, 22));
0402             addItemButton.moveBottomLeft(option.rect.bottomLeft());
0403 
0404             QRect deleteItemButton(QPoint(0, 0), QSize(22, 22));
0405             deleteItemButton.moveBottomRight(option.rect.bottomRight());
0406 
0407             bool addItemButtonClicked = addItemButton.isValid() && addItemButton.contains(mouseEvent->pos());
0408             bool deleteItemButtonClicked = deleteItemButton.isValid() && deleteItemButton.contains(mouseEvent->pos());
0409 
0410             StoryboardModel* sbModel = dynamic_cast<StoryboardModel*>(model);
0411             KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(sbModel, false);
0412             if (leftButton && addItemButtonClicked) {
0413                 sbModel->insertItem(index.parent(), true);
0414                 return true;
0415             }
0416             else if (leftButton && deleteItemButtonClicked) {
0417                 int row = index.parent().row();
0418                 KisRemoveStoryboardCommand *command = new KisRemoveStoryboardCommand(row, sbModel->getData().at(row), sbModel);
0419 
0420                 sbModel->removeItem(index.parent(), command);
0421                 sbModel->pushUndoCommand(command);
0422                 return true;
0423             }
0424         }
0425     }
0426 
0427     if ((event->type() == QEvent::MouseMove) && (index.flags() & Qt::ItemIsEnabled)) {
0428         QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
0429         const bool leftButton = mouseEvent->buttons() & Qt::LeftButton;
0430 
0431         QStyleOptionSlider scrollBarOption = drawCommentHeader(nullptr, option, index);
0432         QRect scrollBarRect = scrollBar(option, scrollBarOption);
0433 
0434         bool lastClickPosInScroll = scrollBarRect.isValid() && scrollBarRect.contains(m_lastDragPos);
0435         bool currClickPosInScroll = scrollBarRect.isValid() && scrollBarRect.contains(mouseEvent->pos());
0436 
0437         if (leftButton && index.parent().isValid() && index.row() >= StoryboardItem::Comments) {
0438             if (lastClickPosInScroll && currClickPosInScroll) {
0439                 int lastValue = model->data(index, Qt::UserRole).toInt();
0440                 int value = lastValue + mouseEvent->pos().y() - m_lastDragPos.y();
0441 
0442                 StoryboardModel* modelSB = dynamic_cast<StoryboardModel*>(model);
0443                 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(modelSB, false);
0444                 if (value >= 0 && value <= scrollBarOption.maximum) {
0445                     modelSB->setCommentScrollData(index, value);
0446                     return true;
0447                 }
0448                 return false;
0449             }
0450             m_lastDragPos = mouseEvent->pos();
0451         }
0452     }
0453 
0454     return false;
0455 }
0456 
0457 //set the existing data in the editor
0458 void StoryboardDelegate::setEditorData(QWidget *editor,
0459                                        const QModelIndex &index) const
0460 {
0461     QVariant value = index.data();
0462     if (index.parent().isValid()) {
0463         int row = index.row();
0464         switch (row)
0465         {
0466         case StoryboardItem::FrameNumber:             //frame thumbnail is uneditable
0467             return;
0468         case StoryboardItem::ItemName:
0469         {
0470             QLineEdit *lineEdit = static_cast<QLineEdit*>(editor);
0471             lineEdit->setText(value.toString());
0472             return;
0473         }
0474         case StoryboardItem::DurationSecond:
0475         case StoryboardItem::DurationFrame:
0476         {
0477             QSpinBox *spinbox = static_cast<QSpinBox*>(editor);
0478             spinbox->setValue(value.toInt());
0479             return;
0480         }
0481         default:             // for comments
0482         {
0483             QTextEdit *textEdit = static_cast<QTextEdit*>(editor);
0484             textEdit->setText(value.toString());
0485             textEdit->moveCursor(QTextCursor::End, QTextCursor::MoveAnchor);
0486             textEdit->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
0487             textEdit->verticalScrollBar()->setProperty("index", index);
0488             connect(textEdit->verticalScrollBar(), SIGNAL(sliderMoved(int)), this, SLOT(slotCommentScrolledTo(int)));
0489             return;
0490         }
0491         }
0492     }
0493 }
0494 
0495 void StoryboardDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
0496                                       const QModelIndex &index) const
0497 {
0498     KIS_ASSERT(model);
0499     QVariant value = index.data();
0500     if (index.parent().isValid()) {
0501         int row = index.row();
0502         switch (row)
0503         {
0504         case StoryboardItem::FrameNumber:             //frame thumbnail is uneditable
0505             return;
0506         case StoryboardItem::ItemName:
0507         {
0508             QLineEdit *lineEdit = static_cast<QLineEdit*>(editor);
0509             QString value = lineEdit->text();
0510             model->setData(index, value, Qt::EditRole);
0511             return;
0512         }
0513         case StoryboardItem::DurationSecond:
0514         case StoryboardItem::DurationFrame:
0515         {
0516             QSpinBox *spinbox = static_cast<QSpinBox*>(editor);
0517             int value = spinbox->value();
0518 
0519             StoryboardModel* sbModel = dynamic_cast<StoryboardModel*>(model);
0520             KIS_SAFE_ASSERT_RECOVER_RETURN(sbModel);
0521             KisStoryboardChildEditCommand *cmd = new KisStoryboardChildEditCommand(index.data(),
0522                                                                                     value,
0523                                                                                     index.parent().row(),
0524                                                                                     index.row(),
0525                                                                                     sbModel);
0526             if (sbModel->setData(index, value)) {
0527                 sbModel->pushUndoCommand(cmd);
0528             }
0529             return;
0530         }
0531         default:             // for comments
0532         {
0533             QTextEdit *textEdit = static_cast<QTextEdit*>(editor);
0534             QString value = textEdit->toPlainText();
0535 
0536             StoryboardModel* sbModel = dynamic_cast<StoryboardModel*>(model);
0537             KIS_SAFE_ASSERT_RECOVER_RETURN(sbModel);
0538             KisStoryboardChildEditCommand *cmd = new KisStoryboardChildEditCommand(index.data(),
0539                                                                                    value,
0540                                                                                    index.parent().row(),
0541                                                                                    index.row(),
0542                                                                                    sbModel);
0543 
0544             if (sbModel->setData(index, value)) {
0545                 sbModel->pushUndoCommand(cmd);
0546             }
0547 
0548             return;
0549         }
0550         }
0551     }
0552 }
0553 
0554 void StoryboardDelegate::updateEditorGeometry(QWidget *editor,
0555                                               const QStyleOptionViewItem &option, const QModelIndex &index) const
0556 {
0557     if (index.row() < StoryboardItem::Comments) {
0558         editor->setGeometry(option.rect);
0559     }
0560     else {                                                //for comment textedits
0561         QRect commentRect = option.rect;
0562         commentRect.setTop(option.rect.top() + option.fontMetrics.height() + 3);
0563         editor->setGeometry(commentRect);
0564     }
0565 }
0566 
0567 void StoryboardDelegate::setView(StoryboardView *view)
0568 {
0569     m_view = view;
0570 }
0571 
0572 QRect StoryboardDelegate::spinBoxUpButton(const QStyleOptionViewItem &option)
0573 {
0574     QStyle *style = option.widget ? option.widget->style() : QApplication::style();
0575     QStyleOptionSpinBox spinOption;
0576     spinOption.rect = option.rect;
0577     QRect rect = style->subControlRect(QStyle::CC_SpinBox, &spinOption,
0578                                        QStyle::QStyle::SC_SpinBoxUp);
0579     rect.moveTopRight(option.rect.topRight());
0580     return rect;
0581 }
0582 
0583 QRect StoryboardDelegate::spinBoxDownButton(const QStyleOptionViewItem &option)
0584 {
0585     QStyle *style = option.widget ? option.widget->style() : QApplication::style();
0586     QStyleOptionSpinBox spinOption;
0587     spinOption.rect = option.rect;
0588     QRect rect = style->subControlRect(QStyle::CC_SpinBox, &spinOption,
0589                                        QStyle::QStyle::SC_SpinBoxDown);
0590     rect.moveBottomRight(option.rect.bottomRight());
0591     return rect;
0592 }
0593 
0594 QRect StoryboardDelegate::spinBoxEditField(const QStyleOptionViewItem &option)
0595 {
0596     QStyle *style = option.widget ? option.widget->style() : QApplication::style();
0597     QStyleOptionSpinBox spinOption;
0598     spinOption.rect = option.rect;
0599     QRect rect = style->subControlRect(QStyle::CC_SpinBox, &spinOption,
0600                                        QStyle::QStyle::SC_SpinBoxEditField);
0601     rect.moveTopLeft(option.rect.topLeft());
0602     return rect;
0603 }
0604 
0605 void StoryboardDelegate::slotCommentScrolledTo(int value) const
0606 {
0607     const QModelIndex index = sender()->property("index").toModelIndex();
0608     KIS_SAFE_ASSERT_RECOVER_RETURN(m_view->model());
0609     StoryboardModel* model = dynamic_cast<StoryboardModel*>(m_view->model());
0610     KIS_SAFE_ASSERT_RECOVER_RETURN(model);
0611     model->setCommentScrollData(index, value);
0612 }
0613 
0614 QRect StoryboardDelegate::scrollBar(const QStyleOptionViewItem &option, QStyleOptionSlider &scrollBarOption) const
0615 {
0616     QStyle *style = option.widget ? option.widget->style() : QApplication::style();
0617     QRect rect = style->subControlRect(QStyle::CC_ScrollBar, &scrollBarOption,
0618                                        QStyle::QStyle::SC_ScrollBarSlider);
0619     rect.moveTopLeft(rect.topLeft() + scrollBarOption.rect.topLeft());
0620     rect.moveTopLeft(rect.topLeft() + option.rect.bottomRight() - scrollBarOption.rect.bottomRight());
0621     return rect;
0622 }
0623 
0624 QRect StoryboardDelegate::scrollDownButton(const QStyleOptionViewItem &option, QStyleOptionSlider &scrollBarOption)
0625 {
0626     QStyle *style = option.widget ? option.widget->style() : QApplication::style();
0627     QRect rect = style->subControlRect(QStyle::CC_ScrollBar, &scrollBarOption,
0628                                        QStyle::QStyle::SC_ScrollBarAddLine);
0629     rect.moveTopLeft(rect.topLeft() + scrollBarOption.rect.topLeft());
0630     rect.moveBottomRight(option.rect.bottomRight());
0631     return rect;
0632 }
0633 
0634 QRect StoryboardDelegate::scrollUpButton(const QStyleOptionViewItem &option, QStyleOptionSlider &scrollBarOption)
0635 {
0636     QStyle *style = option.widget ? option.widget->style() : QApplication::style();
0637     QRect rect = style->subControlRect(QStyle::CC_ScrollBar, &scrollBarOption,
0638                                        QStyle::QStyle::SC_ScrollBarSubLine);
0639     rect.moveTopLeft(rect.topLeft() + scrollBarOption.rect.topLeft());
0640     rect.moveTop(option.rect.bottom() - scrollBarOption.rect.height());
0641     rect.moveRight(option.rect.right());
0642     return rect;
0643 }
0644 
0645 void StoryboardDelegate::setImageSize(QSize imageSize)
0646 {
0647     m_imageSize = imageSize;
0648 }
0649 
0650 bool StoryboardDelegate::isOverlappingActionIcons(const QRect &rect, const QMouseEvent *event)
0651 {
0652     QRect addItemButton(QPoint(0, 0), QSize(22, 22));
0653     addItemButton.moveBottomLeft(rect.bottomLeft());
0654 
0655     QRect deleteItemButton(QPoint(0, 0), QSize(22, 22));
0656     deleteItemButton.moveBottomRight(rect.bottomRight());
0657 
0658     bool addItemButtonHover = addItemButton.isValid() && addItemButton.contains(event->pos());
0659     bool deleteItemButtonHover = deleteItemButton.isValid() && deleteItemButton.contains(event->pos());
0660 
0661     return addItemButtonHover || deleteItemButtonHover;
0662 }
0663 
0664 bool StoryboardDelegate::eventFilter(QObject *editor, QEvent *event)
0665 {
0666     if (event->type() == QEvent::KeyPress) {
0667         QKeyEvent* kEvent = static_cast<QKeyEvent*>(event);
0668         QTextEdit* textEditor = qobject_cast<QTextEdit*>(editor);
0669         if (textEditor && kEvent->key() == Qt::Key_Escape) {
0670             emit commitData(textEditor);
0671             emit closeEditor(textEditor, QAbstractItemDelegate::SubmitModelCache);
0672             return true;
0673         }
0674     }
0675     QStyledItemDelegate::eventFilter(editor, event);
0676     return false;
0677 }