File indexing completed on 2024-04-21 15:23:40

0001 /********************************************************************************
0002  * Copyright (C) 2012-2015 by Stephen Allewell                                  *
0003  * steve.allewell@gmail.com                                                     *
0004  *                                                                              *
0005  * This program is free software; you can redistribute it and/or modify         *
0006  * it under the terms of the GNU General Public License as published by         *
0007  * the Free Software Foundation; either version 2 of the License, or            *
0008  * (at your option) any later version.                                          *
0009  ********************************************************************************/
0010 
0011 
0012 /**
0013  * @file
0014  * Implement the SymbolListWidget class
0015  */
0016 
0017 
0018 /**
0019  * @page library_list_widget SymbolListWidget
0020  * This class implements an extension to the QListWidget class that provides population of the widget
0021  * with the contents of a SymbolLibrary. For each Symbol in the library a QListWidgetItem is created
0022  * with a data item representing the Symbol identifier in the library and an icon at a given size that
0023  * is generated from the Symbol path.
0024  *
0025  * The widget is intended to be used in a dialog or main window and allows selection of a symbol to be
0026  * used for some purpose in the application.
0027  *
0028  * @image html ui-main-library.png "The user interface showing the library tab"
0029  */
0030 
0031 
0032 #include "SymbolListWidget.h"
0033 
0034 #include <QApplication>
0035 #include <QMimeData>
0036 #include <QPainter>
0037 #include <QPalette>
0038 #include <QPen>
0039 
0040 #include "Commands.h"
0041 #include "Symbol.h"
0042 #include "SymbolLibrary.h"
0043 
0044 
0045 /**
0046  * Constructor.
0047  */
0048 SymbolListWidget::SymbolListWidget(QWidget *parent)
0049     :   QListWidget(parent),
0050         m_library(0),
0051         m_lastIndex(0)
0052 {
0053     setResizeMode(QListView::Adjust);
0054     setViewMode(QListView::IconMode);
0055     setIconSize(48);
0056 }
0057 
0058 
0059 /**
0060  * Destructor.
0061  */
0062 SymbolListWidget::~SymbolListWidget()
0063 {
0064 }
0065 
0066 
0067 /**
0068  * Set the size of the icons to be used.
0069  * The base QListWidget has the icon size and grid size set to this value.
0070  * If there are existing items in the QListWidget, they are updated with new icons.
0071  *
0072  * @param size the size in pixels
0073  */
0074 void SymbolListWidget::setIconSize(int size)
0075 {
0076     m_size = size;
0077     QListWidget::setIconSize(QSize(m_size, m_size));
0078     setGridSize(QSize(m_size, m_size));
0079     updateIcons();
0080 }
0081 
0082 
0083 /**
0084  * Populate the QListWidget with the QListWidgetItems for each Symbol in the SymbolLibrary.
0085  * An icon is created for each Symbol.
0086  *
0087  * @param library a pointer to the SymbolLibrary containing the Symbols
0088  */
0089 void SymbolListWidget::loadFromLibrary(SymbolLibrary *library)
0090 {
0091     if (!library) {
0092         return;
0093     }
0094 
0095     m_library = library;
0096 
0097     foreach (qint16 index, library->indexes()) {
0098         addSymbol(index, library->symbol(index));
0099     }
0100 }
0101 
0102 
0103 /**
0104  * Add an individual Symbol to the view.
0105  *
0106  * @param index the index of the Symbol
0107  * @param symbol a const reference to the Symbol to add
0108  */
0109 void SymbolListWidget::addSymbol(qint16 index, const Symbol &symbol)
0110 {
0111     QListWidgetItem *item = createItem(index);
0112     item->setIcon(createIcon(symbol, m_size));
0113 }
0114 
0115 
0116 /**
0117  * Remove a symbol item from the view.
0118  *
0119  * @param index the index of the item to remove
0120  */
0121 void SymbolListWidget::removeSymbol(qint16 index)
0122 {
0123     if (m_items.contains(index)) {
0124         removeItemWidget(m_items.value(index));
0125         delete m_items.take(index);
0126     }
0127 }
0128 
0129 
0130 /**
0131  * If an item for the index currently exists return it otherwise create
0132  * an item to be inserted into the QListWidget.
0133  * The item created has a data entry added representing the index.
0134  * The items are inserted so that the Symbols are sorted by their index.
0135  *
0136  * @param index an index in the SymbolLibrary
0137  *
0138  * @return a pointer to the QListWidgetItem created
0139  */
0140 QListWidgetItem *SymbolListWidget::createItem(qint16 index)
0141 {
0142     if (m_items.contains(index)) {
0143         return m_items.value(index);
0144     }
0145 
0146     QListWidgetItem *item = new QListWidgetItem;
0147     item->setData(Qt::UserRole, index);
0148     m_items.insert(index, item);
0149     int i = index;
0150 
0151     while (++i < m_lastIndex)
0152         if (m_items.contains(i)) {
0153             break;
0154         }
0155 
0156     if (i >= m_lastIndex) {
0157         addItem(item);
0158         m_lastIndex = index;
0159     } else {
0160         insertItem(row(m_items[i]), item);
0161     }
0162 
0163     return item;
0164 }
0165 
0166 
0167 /**
0168  * Create a QIcon for the supplied Symbol.
0169  *
0170  * @param symbol a const reference to a Symbol
0171  * @param size a size for the icon
0172  *
0173  * @return a QIcon
0174  */
0175 QIcon SymbolListWidget::createIcon(const Symbol &symbol, int size)
0176 {
0177     QPalette pal = QApplication::palette();
0178 
0179     QPixmap icon(size, size);
0180     icon.fill(Qt::transparent);
0181 
0182     QPainter p(&icon);
0183     p.setRenderHint(QPainter::Antialiasing, true);
0184     p.scale(size, size);
0185 
0186     QBrush brush = symbol.brush();
0187     QPen pen = symbol.pen();
0188 
0189     brush.setColor(pal.color(QPalette::WindowText));
0190     pen.setColor(pal.color(QPalette::WindowText));
0191 
0192     p.setBrush(brush);
0193     p.setPen(pen);
0194     p.drawPath(symbol.path());
0195     p.end();
0196 
0197     return QIcon(icon);
0198 }
0199 
0200 
0201 /**
0202  * Provide a list of mimetypes that this widget provides when dragging from it.
0203  *
0204  * @return a QStringList containing the mimetype strings
0205  */
0206 QStringList SymbolListWidget::mimeTypes() const
0207 {
0208     QStringList mimetypes;
0209     mimetypes.append("application/kxstitchsymbol");
0210     return mimetypes;
0211 }
0212 
0213 
0214 Qt::DropActions SymbolListWidget::supportedDropActions() const
0215 {
0216     return Qt::CopyAction;
0217 }
0218 
0219 
0220 /**
0221  * Called when dragging items from one QListWidget to another to provide the serialised data.
0222  *
0223  * @param items a QList of pointers to the QListWidgetItems to provide data for
0224  *
0225  * @return a pointer to the QMimeData created
0226  */
0227 QMimeData *SymbolListWidget::mimeData(const QList<QListWidgetItem *> items) const
0228 {
0229     QMimeData *mimeData = new QMimeData;
0230 
0231     QByteArray data;
0232     QDataStream stream(&data, QIODevice::WriteOnly);
0233 
0234     foreach (QListWidgetItem * item, items) {
0235         qint16 index = static_cast<qint16>(item->data(Qt::UserRole).toInt());
0236         Symbol symbol = m_library->symbol(index);
0237         stream << symbol;
0238     }
0239 
0240     mimeData->setData("application/kxstitchsymbol", data);
0241     return mimeData;
0242 }
0243 
0244 
0245 /**
0246  * Called when QListWidgetItems are dragged from one QListWidget to another.
0247  *
0248  * @param index the position index of the dropped item
0249  * @param mimeData a pointer to the serialised data from the source
0250  * @param action the requested drop action, only copying will be implemented
0251  *
0252  * @return @c true if the action is handled, @c false otherwise
0253  */
0254 bool SymbolListWidget::dropMimeData(int index, const QMimeData *mimeData, Qt::DropAction action)
0255 {
0256     Q_UNUSED(index);
0257     Q_UNUSED(action);
0258 
0259     if (mimeData->hasFormat("application/kxstitchsymbol")) {
0260         m_library->undoStack()->push(new DragAndDropCommand(m_library, mimeData));
0261         return true;
0262     }
0263 
0264     return false;
0265 }
0266 
0267 
0268 /**
0269  * Intercept the events system to discover if the theme has changed, this should invoke
0270  * an update to the icons used to display the correct colors.
0271  *
0272  * @param e a pointer to the events
0273  *
0274  * @return @c true if the event was accepted, @c false otherwise
0275  */
0276 bool SymbolListWidget::event(QEvent *e)
0277 {
0278     bool accepted = QListWidget::event(e);
0279 
0280     if (e->type() == QEvent::PaletteChange) {
0281         updateIcons();
0282     }
0283 
0284     return accepted;
0285 }
0286 
0287 
0288 /**
0289  * Generate the icons for all the QListWidgetItems stored in m_items.
0290  */
0291 void SymbolListWidget::updateIcons()
0292 {
0293     QMapIterator<qint16, QListWidgetItem *> i(m_items);
0294 
0295     while (i.hasNext()) {
0296         i.next();
0297         i.value()->setIcon(createIcon(m_library->symbol(i.key()), m_size));
0298     }
0299 }