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

0001 /*
0002  * Copyright (C) 2010-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 #include "LibraryManagerDlg.h"
0012 
0013 #include <QClipboard>
0014 #include <QDir>
0015 #include <QFileInfoList>
0016 #include <QHelpEvent>
0017 #include <QInputDialog>
0018 #include <QMimeData>
0019 #include <QStandardPaths>
0020 #include <QToolTip>
0021 
0022 #include <KHelpClient>
0023 #include <KLocalizedString>
0024 #include <KMessageBox>
0025 #include <kwidgetsaddons_version.h>
0026 
0027 #include "LibraryFilePathsDlg.h"
0028 #include "LibraryListWidgetItem.h"
0029 #include "LibraryPatternPropertiesDlg.h"
0030 #include "LibraryTreeWidgetItem.h"
0031 #include "Pattern.h"
0032 
0033 #include "configuration.h"
0034 
0035 LibraryManagerDlg::LibraryManagerDlg(QWidget *parent)
0036     : QDialog(parent)
0037 {
0038     setWindowTitle(i18n("Library Manager"));
0039 
0040     ui.setupUi(this);
0041 
0042     refreshLibraries();
0043 
0044     ui.LibraryTree->setContextMenuPolicy(Qt::CustomContextMenu);
0045     ui.LibraryIcons->setContextMenuPolicy(Qt::CustomContextMenu);
0046     ui.LibraryIcons->changeIconSize(Configuration::icon_DefaultSize());
0047     ui.IconSizeSlider->setValue(Configuration::icon_DefaultSize());
0048 }
0049 
0050 LibraryTreeWidgetItem *LibraryManagerDlg::currentLibrary()
0051 {
0052     return static_cast<LibraryTreeWidgetItem *>(ui.LibraryTree->currentItem());
0053 }
0054 
0055 bool LibraryManagerDlg::event(QEvent *event)
0056 {
0057     if (event->type() == QEvent::ToolTip) {
0058         QHelpEvent *helpEvent = static_cast<QHelpEvent *>(event);
0059         QString tip;
0060 
0061         if (ui.LibraryTree->topLevelItemCount() == 0) {
0062             tip = i18n(
0063                 "The Library Manager can be used to store\nreusable patterns for insertion into\nnew patterns.\n\nThere are no library categories "
0064                 "defined.\nClick the Help button for information on creating\nand populating libraries.");
0065         } else {
0066             if (ui.LibraryTree->currentItem() == nullptr) {
0067                 tip = i18n("Select a library to show the associated patterns.");
0068             } else if (ui.LibraryIcons->count() == 0) {
0069                 tip = i18n("There are no patterns defined\nfor this library.\n\nClick the Help button for information\non creating and populating libraries.");
0070             }
0071         }
0072 
0073         if (!tip.isEmpty()) {
0074             QToolTip::showText(helpEvent->globalPos(), tip);
0075         } else {
0076             QToolTip::hideText();
0077         }
0078 
0079         return true;
0080     }
0081 
0082     return QWidget::event(event);
0083 }
0084 
0085 void LibraryManagerDlg::hideEvent(QHideEvent *event)
0086 {
0087     KConfigGroup(KSharedConfig::openConfig(), QStringLiteral("DialogSizes")).writeEntry(QStringLiteral("LibraryManagerDlg"), size());
0088 
0089     QDialog::hideEvent(event);
0090 }
0091 
0092 void LibraryManagerDlg::showEvent(QShowEvent *event)
0093 {
0094     QDialog::showEvent(event);
0095 
0096     if (KConfigGroup(KSharedConfig::openConfig(), QStringLiteral("DialogSizes")).hasKey(QStringLiteral("LibraryManagerDlg"))) {
0097         resize(KConfigGroup(KSharedConfig::openConfig(), QStringLiteral("DialogSizes")).readEntry(QStringLiteral("LibraryManagerDlg"), QSize()));
0098     }
0099 }
0100 
0101 void LibraryManagerDlg::setCellSize(double cellWidth, double cellHeight)
0102 {
0103     ui.LibraryIcons->setCellSize(cellWidth, cellHeight);
0104 }
0105 
0106 void LibraryManagerDlg::on_LibraryTree_customContextMenuRequested(const QPoint &position)
0107 {
0108     m_contextMenu.clear();
0109     m_contextMenu.addAction(i18n("New Category"), this, &LibraryManagerDlg::newCategory);
0110 
0111     if ((m_contextTreeItem = static_cast<LibraryTreeWidgetItem *>(ui.LibraryTree->itemAt(position)))) {
0112         m_contextMenu.addAction(i18n("Add to Export List"), this, &LibraryManagerDlg::addLibraryToExportList);
0113         m_contextMenu.addAction(i18n("Properties..."), this, &LibraryManagerDlg::libraryProperties);
0114 
0115         if (QApplication::clipboard()->mimeData()->hasFormat(QStringLiteral("application/kxstitch"))) {
0116             m_contextMenu.addAction(i18n("Paste"), this, &LibraryManagerDlg::pasteFromClipboard);
0117         }
0118     }
0119 
0120     m_contextMenu.popup(QCursor::pos());
0121 }
0122 
0123 void LibraryManagerDlg::on_LibraryIcons_customContextMenuRequested(const QPoint &position)
0124 {
0125     m_contextMenu.clear();
0126 
0127     if ((m_contextListItem = static_cast<LibraryListWidgetItem *>(ui.LibraryIcons->itemAt(position)))) {
0128         m_contextMenu.addAction(i18n("Properties..."), this, &LibraryManagerDlg::patternProperties);
0129         //        m_contextMenu.addAction(i18n("Add to Export List"), this, SLOT(addPatternToExportList()));
0130         //        m_contextMenu.addAction(i18n("Copy"), this, SLOT(copyToClipboard()));
0131         m_contextMenu.addAction(i18n("Delete"), this, &LibraryManagerDlg::deletePattern);
0132         m_contextMenu.popup(QCursor::pos());
0133     } else {
0134         if (QApplication::clipboard()->mimeData()->hasFormat(QStringLiteral("application/kxstitch")) && ui.LibraryTree->selectedItems().count() == 1) {
0135             m_contextMenu.addAction(i18n("Paste"), this, &LibraryManagerDlg::pasteFromClipboard);
0136             m_contextMenu.popup(QCursor::pos());
0137         }
0138     }
0139 }
0140 
0141 void LibraryManagerDlg::on_LibraryTree_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *)
0142 {
0143     ui.LibraryIcons->clear();
0144     LibraryTreeWidgetItem *libraryTreeWidgetItem = dynamic_cast<LibraryTreeWidgetItem *>(current);
0145 
0146     for (LibraryPattern *libraryPattern = libraryTreeWidgetItem->first(); libraryPattern; libraryPattern = libraryTreeWidgetItem->next()) {
0147         LibraryListWidgetItem *libraryListWidgetItem = new LibraryListWidgetItem(ui.LibraryIcons, libraryPattern);
0148         libraryPattern->setLibraryListWidgetItem(libraryListWidgetItem);
0149     }
0150 }
0151 
0152 void LibraryManagerDlg::on_IconSizeSlider_valueChanged(int size)
0153 {
0154     ui.LibraryIcons->changeIconSize(size);
0155 }
0156 
0157 void LibraryManagerDlg::on_DialogButtonBox_rejected()
0158 {
0159     reject();
0160 }
0161 
0162 void LibraryManagerDlg::on_DialogButtonBox_helpRequested()
0163 {
0164     KHelpClient::invokeHelp(QStringLiteral("PatternLibraryDialog"), QStringLiteral("kxstitch"));
0165 }
0166 
0167 void LibraryManagerDlg::newCategory()
0168 {
0169     QString category;
0170 
0171     bool ok = false;
0172     bool exists = false;
0173 
0174     category = QInputDialog::getText(this, i18n("Create Category"), i18n("Category Name"), QLineEdit::Normal, QString(), &ok);
0175 
0176     if (!ok)
0177         return; // user cancelled
0178 
0179     if (m_contextTreeItem) {
0180         for (int i = 0; i < m_contextTreeItem->childCount(); ++i) {
0181             if (m_contextTreeItem->child(i)->text(0) == category) {
0182                 exists = true;
0183             }
0184         }
0185     } else {
0186         QList<QTreeWidgetItem *> rootItems = ui.LibraryTree->findItems(category, Qt::MatchExactly);
0187 
0188         if (!rootItems.isEmpty()) {
0189             exists = true;
0190         }
0191     }
0192 
0193     if (exists) {
0194         KMessageBox::error(this, i18n("This category already exists."), i18n("Category Exists"));
0195         return;
0196     }
0197 
0198     LibraryTreeWidgetItem *newItem;
0199 
0200     if (m_contextTreeItem) {
0201         newItem = new LibraryTreeWidgetItem(m_contextTreeItem, category);
0202     } else {
0203         newItem = new LibraryTreeWidgetItem(ui.LibraryTree, category);
0204     }
0205 
0206     QString path;
0207     QFileInfo fileInfo;
0208 
0209     if (m_contextTreeItem) {
0210         fileInfo.setFile(m_contextTreeItem->path());
0211         path = m_contextTreeItem->path();
0212 
0213         if (!fileInfo.isWritable()) {
0214             path.remove(0, path.indexOf(QLatin1String("/library")));
0215             path.prepend(QStandardPaths::writableLocation(QStandardPaths::DataLocation));
0216         }
0217     } else {
0218         path = QString::fromLatin1("%1/%2").arg(QStandardPaths::writableLocation(QStandardPaths::DataLocation)).arg(QLatin1String("library"));
0219     }
0220 
0221     path = QString::fromLatin1("%1/%2").arg(path, category);
0222 
0223     if (QDir().mkpath(path)) {
0224         newItem->addPath(path);
0225     }
0226 
0227     ui.LibraryTree->setCurrentItem(newItem);
0228 }
0229 
0230 void LibraryManagerDlg::addLibraryToExportList()
0231 {
0232 }
0233 
0234 void LibraryManagerDlg::libraryProperties()
0235 {
0236     QPointer<LibraryFilePathsDlg> dialog = new LibraryFilePathsDlg(this, m_contextTreeItem->text(0), m_contextTreeItem->paths());
0237     dialog->exec();
0238     delete dialog;
0239 }
0240 
0241 void LibraryManagerDlg::pasteFromClipboard()
0242 {
0243     LibraryTreeWidgetItem *item = static_cast<LibraryTreeWidgetItem *>(ui.LibraryTree->currentItem());
0244     Pattern *pattern = new Pattern();
0245     QByteArray data = QApplication::clipboard()->mimeData()->data(QStringLiteral("application/kxstitch"));
0246     QDataStream stream(&data, QIODevice::ReadOnly);
0247     stream >> *pattern;
0248     item->addPattern(new LibraryPattern(pattern));
0249     on_LibraryTree_currentItemChanged(static_cast<QTreeWidgetItem *>(item), nullptr);
0250 }
0251 
0252 void LibraryManagerDlg::patternProperties()
0253 {
0254     LibraryPattern *libraryPattern = m_contextListItem->libraryPattern();
0255     QPointer<LibraryPatternPropertiesDlg> dialog = new LibraryPatternPropertiesDlg(this,
0256                                                                                    libraryPattern->key(),
0257                                                                                    libraryPattern->modifiers(),
0258                                                                                    libraryPattern->baseline(),
0259                                                                                    libraryPattern->pattern()->palette().schemeName(),
0260                                                                                    libraryPattern->pattern()->stitches().width(),
0261                                                                                    libraryPattern->pattern()->stitches().height(),
0262                                                                                    m_contextListItem->icon());
0263 
0264     if (dialog->exec()) {
0265         libraryPattern->setKeyModifiers(dialog->key(), dialog->modifiers());
0266         libraryPattern->setBaseline(dialog->baseline());
0267     }
0268 
0269     delete dialog;
0270 }
0271 
0272 void LibraryManagerDlg::addPatternToExportList()
0273 {
0274 }
0275 
0276 void LibraryManagerDlg::copyToClipboard()
0277 {
0278 }
0279 
0280 void LibraryManagerDlg::deletePattern()
0281 {
0282 #if KWIDGETSADDONS_VERSION >= QT_VERSION_CHECK(5, 100, 0)
0283     if (KMessageBox::warningTwoActions(nullptr,
0284 #else
0285     if (KMessageBox::warningYesNo(nullptr,
0286 #endif
0287                                        i18n("Delete this pattern."),
0288                                        QString(),
0289                                        KStandardGuiItem::del(),
0290                                        KStandardGuiItem::cancel())
0291 #if KWIDGETSADDONS_VERSION >= QT_VERSION_CHECK(5, 100, 0)
0292         == KMessageBox::PrimaryAction) {
0293 #else
0294         == KMessageBox::Yes) {
0295 #endif
0296         static_cast<LibraryTreeWidgetItem *>(ui.LibraryTree->currentItem())->deletePattern(m_contextListItem->libraryPattern());
0297         delete m_contextListItem;
0298     }
0299 }
0300 
0301 void LibraryManagerDlg::refreshLibraries()
0302 {
0303     ui.LibraryTree->clear();
0304     QStringList libraryDirectories = QStandardPaths::locateAll(QStandardPaths::DataLocation, QStringLiteral("library"), QStandardPaths::LocateDirectory);
0305     QStringListIterator libraryDirectoriesIterator(libraryDirectories);
0306 
0307     while (libraryDirectoriesIterator.hasNext()) {
0308         recurseLibraryDirectory(nullptr, libraryDirectoriesIterator.next());
0309     }
0310 }
0311 
0312 void LibraryManagerDlg::recurseLibraryDirectory(LibraryTreeWidgetItem *parent, const QString &path)
0313 {
0314     QDir directory(path);
0315     const QFileInfoList directoryEntries = directory.entryInfoList();
0316     QListIterator<QFileInfo> fileInfoListIterator(directoryEntries);
0317 
0318     while (fileInfoListIterator.hasNext()) {
0319         QFileInfo fileInfo = fileInfoListIterator.next();
0320 
0321         if (fileInfo.isDir()) {
0322             if (fileInfo.fileName() != QLatin1String(".") && fileInfo.fileName() != QLatin1String("..")) {
0323                 LibraryTreeWidgetItem *libraryTreeWidgetItem = nullptr;
0324                 QString subPath = QString::fromLatin1("%1/%2").arg(path, fileInfo.fileName());
0325 
0326                 if (parent) {
0327                     int children = parent->childCount();
0328                     int childIndex = 0;
0329 
0330                     while (childIndex < children) {
0331                         libraryTreeWidgetItem = dynamic_cast<LibraryTreeWidgetItem *>(parent->child(childIndex));
0332 
0333                         if (libraryTreeWidgetItem->text(0) == fileInfo.fileName()) {
0334                             break;
0335                         } else {
0336                             libraryTreeWidgetItem = nullptr;
0337                         }
0338 
0339                         childIndex++;
0340                     }
0341                 } else {
0342                     QList<QTreeWidgetItem *> rootNodes = ui.LibraryTree->findItems(fileInfo.fileName(), Qt::MatchExactly, 0);
0343 
0344                     if (!rootNodes.isEmpty()) {
0345                         libraryTreeWidgetItem = dynamic_cast<LibraryTreeWidgetItem *>(rootNodes[0]);
0346                     }
0347                 }
0348 
0349                 if (libraryTreeWidgetItem == nullptr) {
0350                     if (parent) {
0351                         libraryTreeWidgetItem = new LibraryTreeWidgetItem(parent, fileInfo.fileName());
0352                     } else {
0353                         libraryTreeWidgetItem = new LibraryTreeWidgetItem(ui.LibraryTree, fileInfo.fileName());
0354                         ui.LibraryTree->sortItems(0, Qt::AscendingOrder);
0355                     }
0356                 }
0357 
0358                 libraryTreeWidgetItem->addPath(subPath);
0359                 recurseLibraryDirectory(libraryTreeWidgetItem, subPath);
0360             }
0361         }
0362     }
0363 }
0364 
0365 #include "moc_LibraryManagerDlg.cpp"