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

0001 /*
0002  * Copyright (C) 2003-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 "LibraryFile.h"
0012 
0013 #include <QDataStream>
0014 #include <QFile>
0015 #include <QFileInfo>
0016 #include <QProgressDialog>
0017 
0018 #include <KLocalizedString>
0019 #include <KMessageBox>
0020 
0021 #include <stdlib.h>
0022 
0023 #include "LibraryPattern.h"
0024 
0025 LibraryFile::LibraryFile(const QString &path)
0026     : m_read(false)
0027     , m_path(path)
0028 {
0029     m_exists = QFile::exists(localFile());
0030 }
0031 
0032 LibraryFile::~LibraryFile()
0033 {
0034     if (hasChanged()) {
0035         writeFile();
0036     }
0037 
0038     qDeleteAll(m_libraryPatterns);
0039 }
0040 
0041 QString LibraryFile::path() const
0042 {
0043     return m_path;
0044 }
0045 
0046 bool LibraryFile::isWritable() const
0047 {
0048     return QFileInfo(m_path).isWritable();
0049 }
0050 
0051 void LibraryFile::addPattern(LibraryPattern *libraryPattern)
0052 {
0053     m_libraryPatterns.append(libraryPattern);
0054     writeFile();
0055 }
0056 
0057 void LibraryFile::deletePattern(LibraryPattern *libraryPattern)
0058 {
0059     if (m_libraryPatterns.removeOne(libraryPattern)) {
0060         delete libraryPattern;
0061         writeFile();
0062     }
0063 }
0064 
0065 LibraryPattern *LibraryFile::first()
0066 {
0067     if (!m_read) {
0068         readFile();
0069     }
0070 
0071     m_current = 0;
0072 
0073     if (m_current < m_libraryPatterns.count()) {
0074         return m_libraryPatterns.at(m_current++);
0075     }
0076 
0077     return nullptr;
0078 }
0079 
0080 LibraryPattern *LibraryFile::next()
0081 {
0082     if (m_current < m_libraryPatterns.count()) {
0083         return m_libraryPatterns.at(m_current++);
0084     }
0085 
0086     return nullptr;
0087 }
0088 
0089 void LibraryFile::readFile()
0090 {
0091     if (m_exists) {
0092         bool ok = true;
0093         QFile file(localFile());
0094 
0095         if (file.open(QIODevice::ReadOnly)) {
0096             QDataStream stream(&file);
0097             char header[11];
0098             stream.readRawData(header, 11);
0099 
0100             if (strncmp(header, "KXStitchLib", 11) == 0) {
0101                 qint16 version;
0102                 qint32 count;
0103                 qint32 key; // version 1 of library format
0104                 qint32 modifier; // version 1 of library format
0105                 qint16 baseline; // version 1 of library format
0106                 quint16 checksum; // version 1 of library format
0107                 ok = true;
0108                 QByteArray data;
0109                 LibraryPattern *libraryPattern;
0110 
0111                 QProgressDialog progress(nullptr);
0112                 progress.setLabelText(i18n("Loading Library %1", file.fileName()));
0113 
0114                 stream >> version;
0115 
0116                 switch (version) {
0117                 case 1:
0118                     progress.setRange(file.pos(), file.size());
0119                     progress.setValue(0);
0120                     progress.show();
0121 
0122                     while (!file.atEnd() && ok) {
0123                         stream >> key;
0124                         stream >> modifier;
0125                         stream >> baseline;
0126                         stream >> checksum; // no longer used
0127                         stream >> data;
0128                         Qt::KeyboardModifiers replacedModifiers;
0129 
0130                         if (modifier & 0x0100) {
0131                             replacedModifiers |= Qt::ShiftModifier;
0132                         }
0133 
0134                         if (modifier & 0x0200) {
0135                             replacedModifiers |= Qt::ControlModifier;
0136                         }
0137 
0138                         if (modifier & 0x0400) {
0139                             replacedModifiers |= Qt::AltModifier;
0140                         }
0141 
0142                         if (modifier & 0x0800) {
0143                             replacedModifiers |= Qt::MetaModifier;
0144                         }
0145 
0146                         if (checksum == qChecksum(data.data(), data.size())) {
0147                             m_libraryPatterns.append(new LibraryPattern(data, key, replacedModifiers, baseline));
0148                         } else {
0149                             KMessageBox::error(nullptr,
0150                                                i18n("Failed to read a pattern from the library %1.\n%2", localFile(), file.errorString()),
0151                                                i18n("Failed to read library."));
0152                             ok = false;
0153                         }
0154 
0155                         progress.setValue(file.pos());
0156                     }
0157 
0158                     break;
0159 
0160                 case 100:
0161                     stream >> count;
0162                     progress.setRange(0, count);
0163                     progress.setValue(0);
0164                     progress.show();
0165 
0166                     while (count--) {
0167                         libraryPattern = new LibraryPattern;
0168                         stream >> *libraryPattern;
0169                         m_libraryPatterns.append(libraryPattern);
0170                         progress.setValue(progress.value() + 1);
0171                     }
0172 
0173                     break;
0174 
0175                 default:
0176                     // not supported
0177                     // throw exception
0178                     break;
0179                 }
0180             }
0181 
0182             file.close();
0183             m_read = true;
0184         } else {
0185             KMessageBox::error(nullptr, i18n("The file %1\ncould not be opened for reading.\n%2", localFile(), file.errorString()), i18n("Error opening file"));
0186         }
0187     }
0188 }
0189 
0190 void LibraryFile::writeFile()
0191 {
0192     QFile file(localFile());
0193 
0194     if (file.open(QIODevice::WriteOnly)) { // truncates the file
0195         QDataStream stream(&file);
0196         stream.writeRawData("KXStitchLib", 11);
0197         stream << qint16(version);
0198         stream << qint32(m_libraryPatterns.count());
0199         QListIterator<LibraryPattern *> iterator(m_libraryPatterns);
0200 
0201         while (iterator.hasNext()) {
0202             LibraryPattern *libraryPattern = iterator.next();
0203             stream << *libraryPattern;
0204         }
0205 
0206         file.close();
0207         m_read = true;
0208     } else {
0209         KMessageBox::error(nullptr, i18n("The file %1\ncould not be opened for writing.\n%2", localFile(), file.errorString()), i18n("Error opening file"));
0210     }
0211 }
0212 
0213 QString LibraryFile::localFile() const
0214 {
0215     QFileInfo path(m_path);
0216 
0217     if (path.isDir()) {
0218         return m_path + QLatin1String("/kxstitch.library");
0219     } else {
0220         return m_path;
0221     }
0222 }
0223 
0224 bool LibraryFile::hasChanged()
0225 {
0226     bool changed = false;
0227 
0228     QListIterator<LibraryPattern *> libraryPatternIterator(m_libraryPatterns);
0229 
0230     while (libraryPatternIterator.hasNext()) {
0231         changed = changed | libraryPatternIterator.next()->hasChanged();
0232     }
0233 
0234     return changed;
0235 }