File indexing completed on 2024-05-12 16:36:48

0001 /* This file is part of the KDE project
0002 *
0003 * Copyright (C) 2011 Paul Mendez <paulestebanms@gmail.com>
0004 *
0005 * This library is free software; you can redistribute it and/or
0006 * modify it under the terms of the GNU Library General Public
0007 * License as published by the Free Software Foundation; either
0008 * version 2 of the License, or (at your option) any later version.
0009 *
0010 * This library is distributed in the hope that it will be useful,
0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0013 * Library General Public License for more details.
0014 *
0015 * You should have received a copy of the GNU Library General Public License
0016 * along with this library; see the file COPYING.LIB.  If not, write to
0017 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0018 * Boston, MA 02110-1301, USA.
0019 */
0020 
0021 #include "KPrSlidesManagerView.h"
0022 
0023 //Qt headers
0024 #include <qmath.h>
0025 #include <QPaintEvent>
0026 #include <QScrollBar>
0027 #include <QPainter>
0028 #include <QPen>
0029 #include <QDrag>
0030 
0031 //KF5 headers
0032 #include <klocalizedstring.h>
0033 #include <kiconloader.h>
0034 
0035 KPrSlidesManagerView::KPrSlidesManagerView(QWidget *parent)
0036     : QListView(parent)
0037     , m_draggingFlag(false)
0038     , margin(23)
0039 {
0040     setViewMode(QListView::IconMode);
0041     setFlow(QListView::LeftToRight);
0042     setWrapping(true);
0043     setResizeMode(QListView::Adjust);
0044     setDragEnabled(true);
0045     setAcceptDrops(true);
0046     setDropIndicatorShown(true);
0047     setSpacing(m_itemSize.width()/10);
0048     viewport()->installEventFilter(this);
0049 }
0050 
0051 KPrSlidesManagerView::~KPrSlidesManagerView()
0052 {
0053 }
0054 
0055 void KPrSlidesManagerView::paintEvent(QPaintEvent *event)
0056 {
0057     event->accept();
0058     QListView::paintEvent(event);
0059 
0060     // Paint the line where the slide should go
0061     if (isDragging()) {
0062         QSize size(itemSize().width() + spacing(), itemSize().height() + spacing());
0063         QPair <int, int> m_pair = cursorRowAndColumn();
0064         int numberColumn = m_pair.first;
0065         int numberRow = m_pair.second;
0066         int scrollBarValue = verticalScrollBar()->value();
0067 
0068         QPoint point1(numberColumn * size.width() + spacing() / 2, numberRow * size.height() + spacing() - scrollBarValue);
0069         QPoint point2(numberColumn * size.width() + spacing() / 2, (numberRow + 1) * size.height() - scrollBarValue);
0070         QLineF line(point1, point2);
0071 
0072         QPainter painter(this->viewport());
0073         QPen pen = QPen(palette().brush(QPalette::Highlight), spacing() / 4);
0074         pen.setCapStyle(Qt::RoundCap);
0075         painter.setPen(pen);
0076         painter.setOpacity(0.8);
0077         painter.drawLine(line);
0078     }
0079 }
0080 
0081 void KPrSlidesManagerView::contextMenuEvent(QContextMenuEvent *event)
0082 {
0083     emit requestContextMenu(event);
0084 }
0085 
0086 void KPrSlidesManagerView::mouseDoubleClickEvent(QMouseEvent *event)
0087 {
0088     event->accept();
0089     // do not call QListView::mouseDoubleClickEvent(event); here as this triggers a rename command to be added
0090     emit slideDblClick();
0091 }
0092 
0093 void KPrSlidesManagerView::startDrag(Qt::DropActions supportedActions)
0094 {
0095     const QModelIndexList indexes = selectionModel()->selectedIndexes();
0096     if (!indexes.isEmpty()) {
0097         QMimeData *data = model()->mimeData(indexes);
0098         if (!data) {
0099             return;
0100         }
0101 
0102         QDrag *drag = new QDrag(this);
0103         drag->setPixmap(createDragPixmap());
0104         drag->setMimeData(data);
0105 
0106         //m_dragSource = this;
0107         drag->exec(supportedActions, Qt::CopyAction);
0108     }
0109 }
0110 
0111 void KPrSlidesManagerView::dropEvent(QDropEvent *ev)
0112 {
0113     setDraggingFlag(false);
0114     ev->setDropAction(Qt::IgnoreAction);
0115     ev->accept();
0116 
0117     clearSelection();
0118 
0119     if (!model()) {
0120         return;
0121     }
0122 
0123     int newIndex = cursorSlideIndex();
0124 
0125     if (newIndex >= model()->rowCount(QModelIndex())) {
0126         newIndex = -1;
0127     }
0128 
0129     model()->dropMimeData(ev->mimeData(), Qt::MoveAction, newIndex, -1, QModelIndex());
0130 }
0131 
0132 void KPrSlidesManagerView::dragMoveEvent(QDragMoveEvent *ev)
0133 {
0134     ev->accept();
0135     if (!model()) {
0136         return;
0137     }
0138     QListView::dragMoveEvent(ev);
0139     setDraggingFlag();
0140     viewport()->update();
0141 }
0142 
0143 void KPrSlidesManagerView::dragEnterEvent(QDragEnterEvent *event)
0144 {
0145     event->setDropAction(Qt::MoveAction);
0146     event->accept();
0147 }
0148 
0149 void KPrSlidesManagerView::dragLeaveEvent(QDragLeaveEvent *e)
0150 {
0151     Q_UNUSED(e);
0152     setDraggingFlag(false);
0153 }
0154 
0155 void KPrSlidesManagerView::focusOutEvent(QFocusEvent *event)
0156 {
0157     Q_UNUSED(event);
0158     emit focusLost();
0159 }
0160 
0161 void KPrSlidesManagerView::focusInEvent(QFocusEvent *event)
0162 {
0163     Q_UNUSED(event);
0164     emit focusGot();
0165 }
0166 
0167 void KPrSlidesManagerView::wheelEvent(QWheelEvent *event)
0168 {
0169     if ((event->modifiers() & Qt::ControlModifier) == Qt::ControlModifier) {
0170         if (event->delta() > 0) {
0171             emit zoomIn();
0172         }
0173         else {
0174             emit zoomOut();
0175         }
0176     }
0177     else {
0178         QListView::wheelEvent(event);
0179     }
0180 }
0181 
0182 void KPrSlidesManagerView::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
0183 {
0184     if (!this->selectionModel()->selection().isEmpty()) {
0185         emit itemSelected();
0186     }
0187     else {
0188         emit selectionCleared();
0189     }
0190     QListView::selectionChanged(selected, deselected);
0191 }
0192 
0193 QRect KPrSlidesManagerView::itemSize() const
0194 {
0195     if (model()) {
0196         return (this->visualRect(model()->index(0,0,QModelIndex())));
0197     }
0198     else {
0199         return QRect();
0200     }
0201 }
0202 
0203 void KPrSlidesManagerView::setDraggingFlag(bool flag)
0204 {
0205     m_draggingFlag = flag;
0206 }
0207 
0208 bool KPrSlidesManagerView::isDragging() const
0209 {
0210     return m_draggingFlag;
0211 }
0212 
0213 bool KPrSlidesManagerView::eventFilter(QObject *watched, QEvent *event)
0214 {
0215     if (watched == viewport() && model()) {
0216         switch (event->type()) {
0217         case QEvent::MouseButtonPress: {
0218             QModelIndex item = indexAt(QWidget::mapFromGlobal(QCursor::pos()));
0219             QMouseEvent *mouseEv = static_cast<QMouseEvent *>(event);
0220 
0221             //Left button is used to deselect, but right button needs a selected item for
0222             //context menu actions
0223             if ((item.row() < 0) && (mouseEv->button() != Qt::LeftButton)) {
0224                 // Selects the last item of the row
0225                 QModelIndex last_index = model()->index(qMin(cursorSlideIndex(), model()->rowCount(QModelIndex()) - 1),
0226                                                         0, QModelIndex());
0227                 setCurrentIndex(last_index);
0228                 emit indexChanged(last_index);
0229             }
0230             break;
0231         }
0232         default:
0233             break;
0234         }
0235     }
0236     return QObject::eventFilter(watched, event);
0237 }
0238 
0239 QPixmap KPrSlidesManagerView::createDragPixmap() const
0240 {
0241      const QModelIndexList selectedIndexes = selectionModel()->selectedIndexes();
0242      Q_ASSERT(!selectedIndexes.isEmpty());
0243 
0244      const int itemCount = selectedIndexes.count();
0245 
0246      // If more than one item is dragged, align the items inside a
0247      // rectangular grid. The maximum grid size is limited to 4 x 4 items.
0248      int xCount = 2;
0249      int size = (KIconLoader::SizeHuge + KIconLoader::SizeEnormous) / 2;
0250      if (itemCount > 9) {
0251          xCount = 4;
0252          size = KIconLoader::SizeMedium;
0253      }
0254      else if (itemCount > 4) {
0255          xCount = 3;
0256          size = KIconLoader::SizeLarge;
0257      }
0258 
0259      if (itemCount < xCount) {
0260          xCount = itemCount;
0261      }
0262 
0263      int yCount = itemCount / xCount;
0264      if (itemCount % xCount != 0) {
0265          ++yCount;
0266      }
0267 
0268      if (yCount > xCount) {
0269          yCount = xCount;
0270      }
0271 
0272      // Draw the selected items into the grid cells
0273      QPixmap dragPixmap(xCount * size + xCount - 1, yCount * size + yCount - 1);
0274      dragPixmap.fill(Qt::transparent);
0275 
0276      QPainter painter(&dragPixmap);
0277      int x = 0;
0278      int y = 0;
0279      foreach (const QModelIndex &selectedIndex, selectedIndexes) {
0280          const QIcon icon = (model()->data(selectedIndex, Qt::DecorationRole)).value<QIcon>();
0281          painter.drawPixmap(x, y, icon.pixmap(size, size));
0282 
0283          x += size + 1;
0284          if (x >= dragPixmap.width()) {
0285              x = 0;
0286              y += size + 1;
0287          }
0288          if (y >= dragPixmap.height()) {
0289              break;
0290          }
0291      }
0292 
0293      return dragPixmap;
0294 }
0295 
0296 int KPrSlidesManagerView::cursorSlideIndex() const
0297 {
0298     QPair <int, int> m_pair = cursorRowAndColumn();
0299     int slidesNumber = qFloor((contentsRect().width() - (margin + spacing() - contentsMargins().right())) /
0300                               (itemSize().width() + spacing()));
0301     slidesNumber = qMax(slidesNumber, 1);
0302     return (m_pair.second * slidesNumber + qMin(slidesNumber, m_pair.first));
0303 }
0304 
0305 QPair<int, int> KPrSlidesManagerView::cursorRowAndColumn() const
0306 {
0307     QSize size(itemSize().width() + spacing(), itemSize().height() + spacing());
0308     int slidesNumber = qFloor((contentsRect().width() - (margin + spacing() - contentsMargins().right())) / size.width());
0309     slidesNumber = qMax(slidesNumber, 1);
0310     int scrollBarValue = verticalScrollBar()->value();
0311     QPoint cursorPosition = QWidget::mapFromGlobal(QCursor::pos());
0312     int numberColumn = qFloor(cursorPosition.x() / size.width());
0313     int numberRow = qCeil((cursorPosition.y() + scrollBarValue) / (qreal)size.height()) - 1;
0314     int numberMod = model()->rowCount(QModelIndex()) > 0 ?
0315                 (numberColumn + slidesNumber * numberRow) % (model()->rowCount(QModelIndex())) : 0;
0316 
0317      int totalRows = qCeil((model()->rowCount(QModelIndex())) / (qreal)slidesNumber);
0318 
0319     if (numberColumn > slidesNumber) {
0320         numberColumn = slidesNumber;
0321     }
0322 
0323     if ((numberColumn > numberMod) & (model()->rowCount(QModelIndex()) % slidesNumber != 0)) {
0324         numberColumn = model()->rowCount(QModelIndex()) % slidesNumber;
0325     }
0326 
0327     if (numberRow > totalRows - 1) {
0328         numberRow = totalRows - 1;
0329         numberColumn = model()->rowCount(QModelIndex()) % slidesNumber != 0 ?
0330                     model()->rowCount(QModelIndex()) % slidesNumber : slidesNumber;
0331     }
0332 
0333     return QPair<int,int>(numberColumn, numberRow);
0334 }