File indexing completed on 2024-04-28 04:32:09

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  * @file
0013  * Implement the SymbolListWidget class
0014  */
0015 
0016 /**
0017  * @page library_list_widget SymbolListWidget
0018  * This class implements an extension to the QListWidget class that provides population of the widget
0019  * with the contents of a SymbolLibrary. For each Symbol in the library a QListWidgetItem is created
0020  * with a data item representing the Symbol identifier in the library and an icon at a given size that
0021  * is generated from the Symbol path.
0022  *
0023  * The widget is intended to be used in a dialog or main window and allows selection of a symbol to be
0024  * used for some purpose in the application.
0025  *
0026  * @image html ui-main-library.png "The user interface showing the library tab"
0027  */
0028 
0029 #include "SymbolListWidget.h"
0030 
0031 #include <QApplication>
0032 #include <QPainter>
0033 #include <QPalette>
0034 #include <QPen>
0035 
0036 #include <KLocalizedString>
0037 
0038 #include "Stitch.h"
0039 #include "Symbol.h"
0040 #include "SymbolLibrary.h"
0041 
0042 /**
0043  * Constructor.
0044  */
0045 SymbolListWidget::SymbolListWidget(QWidget *parent)
0046     : QListWidget(parent)
0047     , m_library(nullptr)
0048     , m_lastIndex(0)
0049 {
0050     setResizeMode(QListView::Adjust);
0051     setViewMode(QListView::IconMode);
0052     setIconSize(24);
0053 }
0054 
0055 /**
0056  * Set the size of the icons to be used.
0057  * The base QListWidget has the icon size and grid size set to this value.
0058  *
0059  * @param size the size in pixels
0060  */
0061 void SymbolListWidget::setIconSize(int size)
0062 {
0063     m_size = size;
0064     QListWidget::setIconSize(QSize(m_size, m_size));
0065     setGridSize(QSize(m_size, m_size));
0066 }
0067 
0068 /**
0069  * Populate the QListWidget with the QListWidgetItems for each Symbol in the SymbolLibrary.
0070  * An icon is created for each Symbol.
0071  *
0072  * @param library a pointer to the SymbolLibrary containing the Symbols
0073  */
0074 void SymbolListWidget::loadFromLibrary(SymbolLibrary *library)
0075 {
0076     if (!library) {
0077         return;
0078     }
0079 
0080     m_library = library;
0081     QList<qint16> keys = library->indexes();
0082 
0083     foreach (qint16 index, keys) {
0084         addSymbol(index, library->symbol(index));
0085     }
0086 }
0087 
0088 /**
0089  * Add an individual Symbol to the view.
0090  *
0091  * @param index the index of the Symbol
0092  * @param symbol a const reference to the Symbol to add
0093  * @return a pointer to a QListWidgetItem
0094  */
0095 QListWidgetItem *SymbolListWidget::addSymbol(qint16 index, const Symbol &symbol)
0096 {
0097     QListWidgetItem *item = createItem(index);
0098     item->setIcon(createIcon(symbol, m_size));
0099 
0100     return item;
0101 }
0102 
0103 /**
0104  * Enable the item so that it can be selected clearing the tooltip.
0105  *
0106  * @param index the index of the Symbol
0107  */
0108 void SymbolListWidget::enableItem(qint16 index)
0109 {
0110     if (m_items.contains(index)) {
0111         m_items.value(index)->setFlags(Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
0112         m_items.value(index)->setToolTip(QString());
0113     }
0114 }
0115 
0116 /**
0117  * Disable the item so that it can not be selected adding a tooltip to
0118  * show the user why.
0119  *
0120  * @param index the index of the Symbol
0121  */
0122 void SymbolListWidget::disableItem(qint16 index)
0123 {
0124     if (m_items.contains(index)) {
0125         m_items.value(index)->setFlags(Qt::NoItemFlags);
0126         m_items.value(index)->setToolTip(QString(i18nc("A symbol that has been used", "Used")));
0127     }
0128 }
0129 
0130 /**
0131  * Remove a symbol item from the view.
0132  *
0133  * @param index the index of the item to remove
0134  */
0135 void SymbolListWidget::removeSymbol(qint16 index)
0136 {
0137     if (m_items.contains(index)) {
0138         delete m_items.take(index);
0139     }
0140 }
0141 
0142 /**
0143  * Set an item as the currently selected one.
0144  *
0145  * @param index the index of the item to be current
0146  */
0147 void SymbolListWidget::setCurrent(qint16 index)
0148 {
0149     if (m_items.contains(index)) {
0150         m_items.value(index)->setSelected(true);
0151     }
0152 }
0153 
0154 /**
0155  * If an item for the index currently exists return it otherwise create
0156  * an item to be inserted into the QListWidget.
0157  * The item created has a data entry added representing the index.
0158  * The items are inserted so that the Symbols are sorted by their index.
0159  *
0160  * @param index an index in the SymbolLibrary
0161  *
0162  * @return a pointer to the QListWidgetItem created
0163  */
0164 QListWidgetItem *SymbolListWidget::createItem(qint16 index)
0165 {
0166     if (m_items.contains(index)) {
0167         return m_items.value(index);
0168     }
0169 
0170     QListWidgetItem *item = new QListWidgetItem;
0171     item->setData(Qt::UserRole, index);
0172     m_items.insert(index, item);
0173     int i = index;
0174 
0175     while (++i < m_lastIndex) {
0176         if (m_items.contains(i)) {
0177             break;
0178         }
0179     }
0180 
0181     if (i >= m_lastIndex) {
0182         addItem(item);
0183         m_lastIndex = index;
0184     } else {
0185         insertItem(row(m_items[i]), item);
0186     }
0187 
0188     return item;
0189 }
0190 
0191 /**
0192  * Create a QIcon for the supplied Symbol.
0193  *
0194  * @param symbol a const reference to a Symbol
0195  * @param size a size for the icon
0196  *
0197  * @return a QIcon
0198  */
0199 QIcon SymbolListWidget::createIcon(const Symbol &symbol, int size)
0200 {
0201     QPalette pal = QApplication::palette();
0202 
0203     QPixmap icon(size, size);
0204     icon.fill(Qt::transparent);
0205 
0206     QPainter painter(&icon);
0207     painter.setRenderHint(QPainter::Antialiasing, true);
0208     painter.setWindow(0, 0, 1, 1);
0209 
0210     QBrush brush = symbol.brush();
0211     QPen pen = symbol.pen();
0212 
0213     brush.setColor(pal.color(QPalette::WindowText));
0214     pen.setColor(pal.color(QPalette::WindowText));
0215 
0216     painter.setBrush(brush);
0217     painter.setPen(pen);
0218     painter.drawPath(symbol.path());
0219     painter.end();
0220 
0221     return QIcon(icon);
0222 }
0223 
0224 /**
0225  * Intercept the events system to discover if the theme has changed, this should invoke
0226  * an update to the icons used to display the correct colors.
0227  *
0228  * @param e a pointer to the events
0229  *
0230  * @return @c true if the event was accepted, @c false otherwise
0231  */
0232 bool SymbolListWidget::event(QEvent *e)
0233 {
0234     bool accepted = QListWidget::event(e);
0235 
0236     if (e->type() == QEvent::PaletteChange) {
0237         updateIcons();
0238     }
0239 
0240     return accepted;
0241 }
0242 
0243 /**
0244  * Generate the icons for all the QListWidgetItems stored in m_items.
0245  */
0246 void SymbolListWidget::updateIcons()
0247 {
0248     QMapIterator<qint16, QListWidgetItem *> i(m_items);
0249 
0250     while (i.hasNext()) {
0251         i.next();
0252         i.value()->setIcon(createIcon(m_library->symbol(i.key()), m_size));
0253     }
0254 }