File indexing completed on 2024-04-28 04:33:57

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(nullptr),
0051         m_lastIndex(0)
0052 {
0053     setResizeMode(QListView::Adjust);
0054     setViewMode(QListView::IconMode);
0055     setIconSize(48);
0056 }
0057 
0058 
0059 /**
0060  * Set the size of the icons to be used.
0061  * The base QListWidget has the icon size and grid size set to this value.
0062  * If there are existing items in the QListWidget, they are updated with new icons.
0063  *
0064  * @param size the size in pixels
0065  */
0066 void SymbolListWidget::setIconSize(int size)
0067 {
0068     m_size = size;
0069     QListWidget::setIconSize(QSize(m_size, m_size));
0070     setGridSize(QSize(m_size, m_size));
0071     updateIcons();
0072 }
0073 
0074 
0075 /**
0076  * Populate the QListWidget with the QListWidgetItems for each Symbol in the SymbolLibrary.
0077  * An icon is created for each Symbol.
0078  *
0079  * @param library a pointer to the SymbolLibrary containing the Symbols
0080  */
0081 void SymbolListWidget::loadFromLibrary(SymbolLibrary *library)
0082 {
0083     if (!library) {
0084         return;
0085     }
0086 
0087     m_library = library;
0088 
0089     foreach (qint16 index, library->indexes()) {
0090         addSymbol(index, library->symbol(index));
0091     }
0092 }
0093 
0094 
0095 /**
0096  * Add an individual Symbol to the view.
0097  *
0098  * @param index the index of the Symbol
0099  * @param symbol a const reference to the Symbol to add
0100  */
0101 void SymbolListWidget::addSymbol(qint16 index, const Symbol &symbol)
0102 {
0103     QListWidgetItem *item = createItem(index);
0104     item->setIcon(createIcon(symbol, m_size));
0105 }
0106 
0107 
0108 /**
0109  * Remove a symbol item from the view.
0110  *
0111  * @param index the index of the item to remove
0112  */
0113 void SymbolListWidget::removeSymbol(qint16 index)
0114 {
0115     if (m_items.contains(index)) {
0116         removeItemWidget(m_items.value(index));
0117         delete m_items.take(index);
0118     }
0119 }
0120 
0121 
0122 /**
0123  * If an item for the index currently exists return it otherwise create
0124  * an item to be inserted into the QListWidget.
0125  * The item created has a data entry added representing the index.
0126  * The items are inserted so that the Symbols are sorted by their index.
0127  *
0128  * @param index an index in the SymbolLibrary
0129  *
0130  * @return a pointer to the QListWidgetItem created
0131  */
0132 QListWidgetItem *SymbolListWidget::createItem(qint16 index)
0133 {
0134     if (m_items.contains(index)) {
0135         return m_items.value(index);
0136     }
0137 
0138     QListWidgetItem *item = new QListWidgetItem;
0139     item->setData(Qt::UserRole, index);
0140     m_items.insert(index, item);
0141     int i = index;
0142 
0143     while (++i < m_lastIndex)
0144         if (m_items.contains(i)) {
0145             break;
0146         }
0147 
0148     if (i >= m_lastIndex) {
0149         addItem(item);
0150         m_lastIndex = index;
0151     } else {
0152         insertItem(row(m_items[i]), item);
0153     }
0154 
0155     return item;
0156 }
0157 
0158 
0159 /**
0160  * Create a QIcon for the supplied Symbol.
0161  *
0162  * @param symbol a const reference to a Symbol
0163  * @param size a size for the icon
0164  *
0165  * @return a QIcon
0166  */
0167 QIcon SymbolListWidget::createIcon(const Symbol &symbol, int size)
0168 {
0169     QPalette pal = QApplication::palette();
0170 
0171     QPixmap icon(size, size);
0172     icon.fill(Qt::transparent);
0173 
0174     QPainter p(&icon);
0175     p.setRenderHint(QPainter::Antialiasing, true);
0176     p.scale(size, size);
0177 
0178     QBrush brush = symbol.brush();
0179     QPen pen = symbol.pen();
0180 
0181     brush.setColor(pal.color(QPalette::WindowText));
0182     pen.setColor(pal.color(QPalette::WindowText));
0183 
0184     p.setBrush(brush);
0185     p.setPen(pen);
0186     p.drawPath(symbol.path());
0187     p.end();
0188 
0189     return QIcon(icon);
0190 }
0191 
0192 
0193 /**
0194  * Provide a list of mimetypes that this widget provides when dragging from it.
0195  *
0196  * @return a QStringList containing the mimetype strings
0197  */
0198 QStringList SymbolListWidget::mimeTypes() const
0199 {
0200     QStringList mimetypes;
0201     mimetypes.append(QStringLiteral("application/kxstitchsymbol"));
0202     return mimetypes;
0203 }
0204 
0205 
0206 Qt::DropActions SymbolListWidget::supportedDropActions() const
0207 {
0208     return Qt::CopyAction;
0209 }
0210 
0211 
0212 /**
0213  * Called when dragging items from one QListWidget to another to provide the serialised data.
0214  *
0215  * @param items a QList of pointers to the QListWidgetItems to provide data for
0216  *
0217  * @return a pointer to the QMimeData created
0218  */
0219 QMimeData *SymbolListWidget::mimeData(const QList<QListWidgetItem *> items) const
0220 {
0221     QMimeData *mimeData = new QMimeData;
0222 
0223     QByteArray data;
0224     QDataStream stream(&data, QIODevice::WriteOnly);
0225 
0226     foreach (QListWidgetItem * item, items) {
0227         qint16 index = static_cast<qint16>(item->data(Qt::UserRole).toInt());
0228         Symbol symbol = m_library->symbol(index);
0229         stream << symbol;
0230     }
0231 
0232     mimeData->setData(QStringLiteral("application/kxstitchsymbol"), data);
0233     return mimeData;
0234 }
0235 
0236 
0237 /**
0238  * Called when QListWidgetItems are dragged from one QListWidget to another.
0239  *
0240  * @param index the position index of the dropped item
0241  * @param mimeData a pointer to the serialised data from the source
0242  * @param action the requested drop action, only copying will be implemented
0243  *
0244  * @return @c true if the action is handled, @c false otherwise
0245  */
0246 bool SymbolListWidget::dropMimeData(int index, const QMimeData *mimeData, Qt::DropAction action)
0247 {
0248     Q_UNUSED(index);
0249     Q_UNUSED(action);
0250 
0251     if (mimeData->hasFormat(QStringLiteral("application/kxstitchsymbol"))) {
0252         m_library->undoStack()->push(new DragAndDropCommand(m_library, mimeData));
0253         return true;
0254     }
0255 
0256     return false;
0257 }
0258 
0259 
0260 /**
0261  * Intercept the events system to discover if the theme has changed, this should invoke
0262  * an update to the icons used to display the correct colors.
0263  *
0264  * @param e a pointer to the events
0265  *
0266  * @return @c true if the event was accepted, @c false otherwise
0267  */
0268 bool SymbolListWidget::event(QEvent *e)
0269 {
0270     bool accepted = QListWidget::event(e);
0271 
0272     if (e->type() == QEvent::PaletteChange) {
0273         updateIcons();
0274     }
0275 
0276     return accepted;
0277 }
0278 
0279 
0280 /**
0281  * Generate the icons for all the QListWidgetItems stored in m_items.
0282  */
0283 void SymbolListWidget::updateIcons()
0284 {
0285     QMapIterator<qint16, QListWidgetItem *> i(m_items);
0286 
0287     while (i.hasNext()) {
0288         i.next();
0289         i.value()->setIcon(createIcon(m_library->symbol(i.key()), m_size));
0290     }
0291 }