File indexing completed on 2024-04-21 04:32:04

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 "Document.h"
0012 
0013 #include <QDataStream>
0014 #include <QFile>
0015 #include <QVariant>
0016 
0017 #include <KLocalizedString>
0018 #include <KMessageBox>
0019 
0020 #include "Editor.h"
0021 #include "Exceptions.h"
0022 #include "Floss.h"
0023 #include "FlossScheme.h"
0024 #include "Layers.h"
0025 #include "Palette.h"
0026 #include "Preview.h"
0027 #include "SchemeManager.h"
0028 
0029 Document::Document()
0030     : m_editor(nullptr)
0031     , m_palette(nullptr)
0032     , m_preview(nullptr)
0033     , m_pattern(nullptr)
0034 {
0035     initialiseNew();
0036 }
0037 
0038 Document::~Document()
0039 {
0040     delete m_pattern;
0041 }
0042 
0043 void Document::initialiseNew()
0044 {
0045     m_undoStack.clear();
0046 
0047     m_backgroundImages.clear();
0048     m_printerConfiguration = PrinterConfiguration();
0049 
0050     delete m_pattern;
0051     m_pattern = new Pattern(this);
0052 
0053     QString scheme = Configuration::palette_DefaultScheme();
0054 
0055     if (SchemeManager::scheme(scheme) == nullptr) {
0056         scheme = SchemeManager::schemes().at(scheme.toInt());
0057     }
0058 
0059     m_pattern->palette().setSchemeName(scheme);
0060 
0061     double documentWidth = Configuration::document_Width();
0062     double documentHeight = Configuration::document_Height();
0063 
0064     double horizontalClothCount = Configuration::editor_HorizontalClothCount();
0065     double verticalClothCount = Configuration::editor_VerticalClothCount();
0066     Configuration::EnumEditor_ClothCountUnits::type clothCountUnits = Configuration::editor_ClothCountUnits();
0067 
0068     if (clothCountUnits == Configuration::EnumEditor_ClothCountUnits::Default) {
0069         clothCountUnits = (QLocale::system().measurementSystem() == QLocale::MetricSystem) ? Configuration::EnumEditor_ClothCountUnits::Centimeters
0070                                                                                            : Configuration::EnumEditor_ClothCountUnits::Inches;
0071     }
0072 
0073     switch (Configuration::document_UnitsFormat()) {
0074     case Configuration::EnumDocument_UnitsFormat::Stitches:
0075         // nothing needs to be done to convert these values
0076         break;
0077 
0078     case Configuration::EnumDocument_UnitsFormat::Inches:
0079         documentWidth *= horizontalClothCount;
0080         documentHeight *= verticalClothCount;
0081 
0082         if (clothCountUnits == Configuration::EnumEditor_ClothCountUnits::Centimeters) {
0083             documentWidth *= 2.54;
0084             documentHeight *= 2.54;
0085         }
0086 
0087         break;
0088 
0089     case Configuration::EnumDocument_UnitsFormat::Centimeters:
0090         documentWidth *= horizontalClothCount;
0091         documentHeight *= verticalClothCount;
0092 
0093         if (clothCountUnits == Configuration::EnumEditor_ClothCountUnits::Inches) {
0094             documentWidth /= 2.54;
0095             documentHeight /= 2.54;
0096         }
0097 
0098         break;
0099 
0100     default: // Avoid compiler warning about unhandled value
0101         break;
0102     }
0103 
0104     m_pattern->stitches().resize(static_cast<int>(documentWidth), static_cast<int>(documentHeight));
0105 
0106     setProperty(QStringLiteral("unitsFormat"), Configuration::document_UnitsFormat());
0107     setProperty(QStringLiteral("title"), QString());
0108     setProperty(QStringLiteral("author"), QString());
0109     setProperty(QStringLiteral("copyright"), QString());
0110     setProperty(QStringLiteral("fabric"), QString());
0111     setProperty(QStringLiteral("fabricColor"), Configuration::editor_BackgroundColor());
0112     setProperty(QStringLiteral("instructions"), QString());
0113     setProperty(QStringLiteral("cellHorizontalGrouping"), Configuration::editor_CellHorizontalGrouping());
0114     setProperty(QStringLiteral("cellVerticalGrouping"), Configuration::editor_CellVerticalGrouping());
0115     setProperty(QStringLiteral("horizontalClothCount"), Configuration::editor_HorizontalClothCount());
0116     setProperty(QStringLiteral("verticalClothCount"), Configuration::editor_VerticalClothCount());
0117     setProperty(QStringLiteral("clothCountUnits"), clothCountUnits);
0118     setProperty(QStringLiteral("clothCountLink"), Configuration::editor_ClothCountLink());
0119     setProperty(QStringLiteral("thickLineColor"), Configuration::editor_ThickLineColor());
0120     setProperty(QStringLiteral("thinLineColor"), Configuration::editor_ThinLineColor());
0121 
0122     setUrl(QUrl(i18n("Untitled")));
0123 }
0124 
0125 QUndoStack &Document::undoStack()
0126 {
0127     return m_undoStack;
0128 }
0129 
0130 void Document::setUrl(const QUrl &url)
0131 {
0132     m_url = url;
0133 }
0134 
0135 QUrl Document::url() const
0136 {
0137     return m_url;
0138 }
0139 
0140 void Document::addView(Editor *editor)
0141 {
0142     m_editor = editor;
0143 }
0144 
0145 void Document::addView(Palette *palette)
0146 {
0147     m_palette = palette;
0148 }
0149 
0150 void Document::addView(Preview *preview)
0151 {
0152     m_preview = preview;
0153 }
0154 
0155 Editor *Document::editor() const
0156 {
0157     return m_editor;
0158 }
0159 
0160 Palette *Document::palette() const
0161 {
0162     return m_palette;
0163 }
0164 
0165 Preview *Document::preview() const
0166 {
0167     return m_preview;
0168 }
0169 
0170 BackgroundImages &Document::backgroundImages()
0171 {
0172     return m_backgroundImages;
0173 }
0174 
0175 Pattern *Document::pattern()
0176 {
0177     return m_pattern;
0178 }
0179 
0180 const PrinterConfiguration &Document::printerConfiguration() const
0181 {
0182     return m_printerConfiguration;
0183 }
0184 
0185 void Document::setPrinterConfiguration(const PrinterConfiguration &printerConfiguration)
0186 {
0187     m_printerConfiguration = printerConfiguration;
0188 }
0189 
0190 void Document::readKXStitch(QDataStream &stream)
0191 {
0192     initialiseNew();
0193 
0194     char header[30];
0195     stream.readRawData(header, 30);
0196 
0197     if (strncmp(header, "KXStitchDoc", 11) == 0) {
0198         // a current KXStitchDoc format file
0199         stream.device()->seek(11);
0200         Layers layers;
0201         qint32 version;
0202         stream >> version;
0203 
0204         switch (version) {
0205         case 104:
0206             stream.setVersion(QDataStream::Qt_4_0); // maintain consistancy in the qt types
0207             stream >> m_properties;
0208             stream >> m_backgroundImages;
0209             stream >> *m_pattern;
0210             stream >> m_printerConfiguration;
0211             break;
0212 
0213         case 103:
0214             stream.setVersion(QDataStream::Qt_4_0); // maintain consistancy in the qt types
0215             stream >> m_properties;
0216             stream >> m_backgroundImages;
0217             stream >> m_pattern->palette();
0218             stream >> m_pattern->stitches();
0219             stream >> m_printerConfiguration;
0220             break;
0221 
0222         case 102:
0223             stream.setVersion(QDataStream::Qt_4_0); // maintain consistancy in the qt types
0224             stream >> m_properties;
0225             stream >> layers;
0226             stream >> m_backgroundImages;
0227             stream >> m_pattern->palette();
0228             stream >> m_pattern->stitches();
0229             stream >> m_printerConfiguration;
0230             break;
0231 
0232         case 101:
0233             stream.setVersion(QDataStream::Qt_4_0); // maintain consistancy in the qt types
0234             [[gnu::fallthrough]]; // flow through to version 100
0235 
0236         case 100:
0237             stream >> m_properties;
0238             stream >> layers;
0239             stream >> m_backgroundImages;
0240             stream >> m_pattern->palette();
0241             stream >> m_pattern->stitches();
0242             break;
0243 
0244         default:
0245             throw InvalidFileVersion(QString(i18n("KXStitch version %1", version)));
0246             break;
0247         }
0248     } else if (strncmp(header, "\x00\x00\x00\x10\x00\x4B\x00\x58\x00\x53\x00\x74\x00\x69\x00\x74\x00\x63\x00\x68", 20) == 0) { // QString("KXStitch")
0249         stream.device()->seek(20);
0250         qint16 version;
0251         stream >> version;
0252 
0253         switch (version) {
0254         case 2:
0255             readKXStitchV2File(stream);
0256             break;
0257 
0258         case 3:
0259             readKXStitchV3File(stream);
0260             break;
0261 
0262         case 4:
0263             readKXStitchV4File(stream);
0264             break;
0265 
0266         case 5:
0267             readKXStitchV5File(stream);
0268             break;
0269 
0270         case 6:
0271             readKXStitchV6File(stream);
0272             break;
0273 
0274         case 7:
0275             readKXStitchV7File(stream);
0276             break;
0277 
0278         default:
0279             throw InvalidFileVersion(QString(i18n("KXStitch version %1", version)));
0280             break;
0281         }
0282     } else {
0283         throw InvalidFile();
0284     }
0285 }
0286 
0287 void Document::readPCStitch(QDataStream &stream)
0288 {
0289     initialiseNew();
0290 
0291     char header[23];
0292     stream.readRawData(header, 23);
0293 
0294     if (strncmp(header, "PCStitch 5 Pattern File", 23) == 0) {
0295         readPCStitch5File(stream);
0296     } else if (strncmp(header, "PCStitch 6 Pattern File", 23) == 0) {
0297         readPCStitch6File(stream);
0298     } else if (strncmp(header, "PCStitch 7 Pattern File", 23) == 0) {
0299         readPCStitch7File(stream);
0300     } else {
0301         throw InvalidFile();
0302     }
0303 }
0304 
0305 void Document::write(QDataStream &stream)
0306 {
0307     stream.setVersion(QDataStream::Qt_4_0); // maintain consistancy in the qt types
0308     stream.writeRawData("KXStitchDoc", 11);
0309     stream << version;
0310     stream << m_properties;
0311     stream << m_backgroundImages;
0312     stream << *m_pattern;
0313     stream << m_printerConfiguration;
0314 
0315     if (stream.status() != QDataStream::Ok) {
0316         throw FailedWriteFile(stream.status());
0317     }
0318 }
0319 
0320 QVariant Document::property(const QString &name) const
0321 {
0322     QVariant p;
0323 
0324     if (m_properties.contains(name)) {
0325         p = m_properties[name];
0326     } else {
0327         qDebug() << "Asked for non existing property" << name;
0328     }
0329 
0330     return p;
0331 }
0332 
0333 void Document::setProperty(const QString &name, const QVariant &value)
0334 {
0335     m_properties[name] = value;
0336 }
0337 
0338 void Document::readPCStitch5File(QDataStream &stream)
0339 {
0340     /* File Format
0341         uchar[256]      // header 'PCStitch 5 Pattern File'
0342                         // other information is contained here
0343         uchar[4]        // unknown
0344         uchar[4]        // unknown, there is something unique to each file here
0345         quint16         // pattern width;
0346         quint16         // pattern height;
0347         quint16         // cloth count width;
0348         quint16         // cloth count height;
0349         quint16         // string length
0350         char[]          // author
0351         quint16         // string length
0352         char[]          // copyright
0353         quint16         // string length
0354         char[]          // title
0355         quint16         // string length
0356         char[]          // fabric
0357         quint16         // string length
0358         char[]          // instructions
0359         char[25]        // 'PCStitch 5 Floss Palette!'
0360         quint16         // palette entries
0361         char[10]        // 'DMC       '
0362         char[10]        // 'Anchor    '
0363         char[10]        // 'Coates    '
0364         quint16         // string length
0365         char[]          // symbol font
0366         uchar[4]        // unknown
0367 
0368         struct paletteEntry {
0369             uchar[4]    // RGBA
0370             char[10];   // dmc color name
0371             char[10];   // anchor color name
0372             char[10];   // coates color name
0373             char[50];   // color description
0374             char        // symbol
0375             quint16     // number of strands for stitches
0376             quint16     // number of strands for backstitches
0377         } repeated for the number of palette entries
0378 
0379         struct stitches {
0380             quint16     // stitch count in columns from top left downward
0381             quint8      // color, 1 based index of color list, 0xFF for none
0382             quint8      // stitch type, 0xFF for none
0383         } repeat until sum of stitchCount == width * height;
0384 
0385         quint32 extras
0386         struct extra {
0387             quint16     // x coordinate, 1 based index of cell
0388             quint16     // y coordinate, 1 based index of cell
0389             struct quadrant {
0390                 quint8  // color, 1 based index of color list, 0xFF for none
0391                 quint8  // stitch type, 0xFF for none
0392             } repeated 4 times
0393         } repeated for extras
0394 
0395         quint32 knots
0396         struct knot {
0397             quint16     // x coordinate, 1 based index of snap points
0398             quint16     // y coordinate, 1 based index of snap points
0399             quint8      // color, 1 based index of color list
0400         } repeated for knots
0401 
0402         quint32 backstitches
0403         struct backstitch {
0404             quint16     // start x, 1 based index of cell
0405             quint16     // start y, 1 based index of cell
0406             quint16     // start position, (1-9) based on snap points
0407             quint16     // end x, 1 based index of cell
0408             quint16     // end y, 1 based index of cell
0409             quint16     // end position, (1-9) based on snap points
0410             quint8      // color, 1 based index of color list
0411         } repeat for backstitches
0412 
0413         uchar[4]        // unknown;
0414         uchar[4]        // unknown;
0415     */
0416     stream.setByteOrder(QDataStream::LittleEndian);
0417     stream.device()->seek(256);
0418 
0419     quint32 unknown32;
0420     stream >> unknown32;
0421     stream >> unknown32;
0422 
0423     quint16 width;
0424     quint16 height;
0425     stream >> width;
0426     stream >> height;
0427 
0428     m_pattern->stitches().resize(width, height);
0429     setProperty(QStringLiteral("unitsFormat"), Configuration::EnumDocument_UnitsFormat::Stitches);
0430 
0431     quint16 clothCount;
0432     stream >> clothCount;
0433     setProperty(QStringLiteral("horizontalClothCount"), double(clothCount));
0434     stream >> clothCount;
0435     setProperty(QStringLiteral("verticalClothCount"), double(clothCount));
0436     setProperty(QStringLiteral("clothCountUnits"), Configuration::EnumEditor_ClothCountUnits::Inches);
0437 
0438     setProperty(QStringLiteral("author"), readPCStitchString(stream));
0439     setProperty(QStringLiteral("copyright"), readPCStitchString(stream));
0440     setProperty(QStringLiteral("title"), readPCStitchString(stream));
0441     setProperty(QStringLiteral("fabric"), readPCStitchString(stream));
0442     setProperty(QStringLiteral("fabricColor"), QColor(Qt::white));
0443 
0444     QString instructions = readPCStitchString(stream);
0445 
0446     if (!instructions.isEmpty()) {
0447         int index = instructions.indexOf(QLatin1String("}}")); // end of font defs
0448         index += 4; // skip paste }} and CR LF
0449         index = instructions.indexOf(QLatin1Char('}'), index); // end of color table defs
0450         index += 3; // skip paste } and CR LF
0451         index = instructions.indexOf(QLatin1Char(' '), index); // find first space - end of text def
0452         index++; // and skip past it
0453                  // index should now point to the first character of the instructions
0454         instructions = instructions.remove(0, index);
0455         instructions.truncate(instructions.length() - 10);
0456     }
0457 
0458     setProperty(QStringLiteral("instructions"), instructions);
0459 
0460     char buffer[51];
0461     stream.readRawData(buffer, 25);
0462 
0463     if (strncmp(buffer, "PCStitch 5 Floss Palette!", 25) == 0) {
0464         quint16 colors;
0465         stream >> colors;
0466 
0467         stream.readRawData(buffer, 30); // this should be 'DMC       Anchor    Coates    '
0468 
0469         QString fontName = readPCStitchString(stream); // the font name, usually 'PCStitch Symbols'
0470 
0471         m_pattern->palette().setSchemeName(QStringLiteral("DMC")); // assume this palette will be DMC
0472         FlossScheme *scheme = SchemeManager::scheme(QStringLiteral("DMC"));
0473 
0474         if (scheme == nullptr) {
0475             throw FailedReadFile(QString(i18n("The floss scheme DMC was not found"))); // this shouldn't happen because DMC should always be available
0476         }
0477 
0478         stream >> unknown32;
0479 
0480         for (int i = 0; i < colors; i++) {
0481 #pragma pack(push)
0482 #pragma pack(1)
0483             struct PALETTE_ENTRY {
0484                 unsigned char RGBA[4];
0485                 char colorName[30];
0486                 char colorDescription[50];
0487                 unsigned char symbol;
0488                 unsigned short stitchStrands;
0489                 unsigned short backstitchStrands;
0490             } paletteEntry;
0491 #pragma pack(pop)
0492 
0493             stream.readRawData(reinterpret_cast<char *>(&paletteEntry), sizeof(struct PALETTE_ENTRY));
0494 
0495             QColor color(int(paletteEntry.RGBA[0]), int(paletteEntry.RGBA[1]), int(paletteEntry.RGBA[2]));
0496             QString colorName = QString::fromLatin1(paletteEntry.colorName, 10).trimmed();
0497 
0498             if (colorName == QLatin1String("White")) {
0499                 colorName = QLatin1String("Blanc"); // fix colorName
0500             }
0501 
0502             if (colorName == QLatin1String("5200")) {
0503                 colorName = QLatin1String("B5200"); // fix colorName
0504             }
0505 
0506             Floss *floss = scheme->find(colorName);
0507 
0508             if (floss == nullptr) {
0509                 floss = scheme->convert(color);
0510             }
0511 
0512             colorName = floss->name();
0513             DocumentFloss *documentFloss =
0514                 new DocumentFloss(colorName,
0515                                   m_pattern->palette().freeSymbol(),
0516                                   Qt::SolidLine,
0517                                   (paletteEntry.stitchStrands) ? paletteEntry.stitchStrands : Configuration::palette_StitchStrands(),
0518                                   (paletteEntry.backstitchStrands) ? paletteEntry.backstitchStrands : Configuration::palette_BackstitchStrands());
0519             documentFloss->setFlossColor(floss->color());
0520             m_pattern->palette().add(i, documentFloss);
0521         }
0522     } else {
0523         throw FailedReadFile(QString(i18n("Invalid data read.")));
0524     }
0525 
0526     m_pattern->palette().setCurrentIndex(-1);
0527 
0528     Stitch::Type stitchType[] = {Stitch::Delete,
0529                                  Stitch::Full,
0530                                  Stitch::TL3Qtr,
0531                                  Stitch::TR3Qtr,
0532                                  Stitch::BL3Qtr,
0533                                  Stitch::BR3Qtr,
0534                                  Stitch::TBHalf,
0535                                  Stitch::BTHalf,
0536                                  Stitch::Delete,
0537                                  Stitch::TLQtr,
0538                                  Stitch::TRQtr,
0539                                  Stitch::BLQtr,
0540                                  Stitch::BRQtr}; // conversion of PCStitch to KXStitch
0541 
0542     int documentWidth = m_pattern->stitches().width();
0543     int documentHeight = m_pattern->stitches().height();
0544     int cells = documentWidth * documentHeight;
0545 
0546     quint16 cellCount;
0547 
0548     for (int i = 0; i < cells; i += cellCount) {
0549         quint8 color;
0550         quint8 type;
0551 
0552         stream >> cellCount;
0553         stream >> color;
0554         stream >> type;
0555 
0556         if (type != 0xff) {
0557             for (int c = 0; c < cellCount; c++) {
0558                 int xc = (i + c) / documentHeight;
0559                 int yc = (i + c) % documentHeight;
0560                 m_pattern->stitches().addStitch(QPoint(xc, yc), stitchType[type], color - 1); // color-1 because PCStitch uses 1 based array
0561             }
0562         }
0563     }
0564 
0565     quint32 extras;
0566     stream >> extras;
0567 
0568     while (extras--) {
0569         quint16 x;
0570         quint16 y;
0571         quint8 color;
0572         quint8 type;
0573 
0574         stream >> x;
0575         stream >> y;
0576 
0577         for (int dx = 0; dx < 4; dx++) {
0578             stream >> color;
0579             stream >> type;
0580 
0581             if (type != 0xff) {
0582                 m_pattern->stitches().addStitch(QPoint(x - 1, y - 1), stitchType[type], color - 1);
0583             }
0584         }
0585     }
0586 
0587     // read french knots
0588 
0589     quint32 knots;
0590     stream >> knots;
0591 
0592     while (knots--) {
0593         quint16 x;
0594         quint16 y;
0595         quint8 color;
0596 
0597         stream >> x;
0598         stream >> y;
0599         stream >> color;
0600         m_pattern->stitches().addFrenchKnot(QPoint(x - 1, y - 1), color - 1);
0601     }
0602 
0603     // read backstitches
0604 
0605     quint32 backstitches;
0606     stream >> backstitches;
0607 
0608     while (backstitches--) {
0609         quint16 sx;
0610         quint16 sy;
0611         quint16 sp;
0612         quint16 ex;
0613         quint16 ey;
0614         quint16 ep;
0615         quint8 color;
0616         stream >> sx >> sy >> sp >> ex >> ey >> ep >> color;
0617         m_pattern->stitches().addBackstitch(QPoint(--sx * 2 + ((sp - 1) % 3), --sy * 2 + ((sp - 1) / 3)),
0618                                             QPoint(--ex * 2 + ((ep - 1) % 3), --ey * 2 + ((ep - 1) / 3)),
0619                                             color - 1);
0620     }
0621 
0622     if (stream.status() != QDataStream::Ok) {
0623         throw FailedReadFile(QString(i18n("Stream error")));
0624     }
0625 }
0626 
0627 void Document::readPCStitch6File(QDataStream &stream)
0628 {
0629     /* File Format
0630         uchar[256]      // header 'PCStitch 6 Pattern File'
0631                         // other information is contained here
0632         uchar[4]        // unknown
0633         uchar[4]        // unknown, there is something unique to each file here
0634         quint16         // pattern width
0635         quint16         // pattern height
0636         quint16         // cloth count width
0637         quint16         // cloth count height
0638         quint16         // string length
0639         char[]          // author
0640         quint16         // string length
0641         char[]          // copyright
0642         quint16         // string length
0643         char[]          // title
0644         quint16         // string length
0645         char[]          // fabric
0646         quint16         // string length
0647         char[]          // instructions
0648         char[25]        // 'PCStitch 6 Floss Palette!'
0649         quint16         // unknown
0650         char[30]        // 'DMC' padded with spaces
0651         char[10]        // scheme
0652         quint16         // palette entries
0653         quint16         // string length
0654         char[]          // symbol font
0655         uchar[4]        // unknown
0656 
0657         struct paletteEntry {
0658             char[30]    // color description
0659             uchar[4]    // RGBA
0660             char[10]    // color name
0661             uchar[65]   // unknown
0662                         // 59 unknown
0663                         // quint16 stitchStrands
0664                         // quint16 backstitchStrands
0665                         // quint16 possibly palette index (seems to increment from 1 to the number of palette entries, but odd files don't)
0666             char[30]    // color description
0667             uchar[5]    // unknown
0668             uchar[25]   // some color  // Black <padded with spaces> (possibly symbol color)
0669         } repeated for the number of palette entries
0670 
0671         struct stitches {
0672             quint16     // stitch count in columns from top left downward
0673             quint8      // color, 1 based index of color list, 0xFF for none
0674             quint8      // stitch type, 0xFF for none
0675         } repeated until sum of stitchCount == width * height
0676 
0677         quint32 extras
0678         struct extra {
0679             quint16     // x coordinate, 1 based index of cell
0680             quint16     // y coordinate, 1 based index of cell
0681             struct quadrant {
0682                 quint8  // color, 1 based index of color list, 0xFF for none
0683                 quint8  // stitch type, 0xFF for none
0684             } repeated 4 times
0685         } repeated for extras
0686 
0687         quint32         // unknown
0688 
0689         quint32 knots
0690         struct knot {
0691             quint16     // x coordinate, 1 based index of snap points
0692             quint16     // y coordinate, 1 based index of snap points
0693             quint8      // color, 1 based index of color list
0694         } repeated for knots
0695 
0696         uint32 backstitches
0697         struct backstitch {
0698             quint16     // start x, 1 based index of cell
0699             quint16     // start y, 1 based index of cell
0700             quint16     // start position, (1..9) based on snap points
0701             quint16     // end x, 1 based index of cell
0702             quint16     // end y, 1 based index of cell
0703             quint16     // end position, (1..9) based on snap points
0704             quint16     // color, 1 based index of color list
0705         } repeat for backstitches
0706 
0707         uchar[4]        // unknown
0708         uchar[4]        // unknown
0709     */
0710     stream.setByteOrder(QDataStream::LittleEndian);
0711     stream.device()->seek(256);
0712 
0713     quint16 unknown16;
0714     quint32 unknown32;
0715 
0716     stream >> unknown32;
0717     stream >> unknown32;
0718 
0719     quint16 width;
0720     quint16 height;
0721     stream >> width;
0722     stream >> height;
0723 
0724     m_pattern->stitches().resize(width, height);
0725     setProperty(QStringLiteral("unitsFormat"), Configuration::EnumDocument_UnitsFormat::Stitches);
0726 
0727     quint16 clothCount;
0728     stream >> clothCount;
0729     setProperty(QStringLiteral("horizontalClothCount"), double(clothCount));
0730     stream >> clothCount;
0731     setProperty(QStringLiteral("verticalClothCount"), double(clothCount));
0732     setProperty(QStringLiteral("clothCountUnits"), Configuration::EnumEditor_ClothCountUnits::Inches);
0733 
0734     setProperty(QStringLiteral("author"), readPCStitchString(stream));
0735     setProperty(QStringLiteral("copyright"), readPCStitchString(stream));
0736     setProperty(QStringLiteral("title"), readPCStitchString(stream));
0737     setProperty(QStringLiteral("fabric"), readPCStitchString(stream));
0738     setProperty(QStringLiteral("fabricColor"), QColor(Qt::white));
0739 
0740     QString instructions = readPCStitchString(stream);
0741 
0742     if (!instructions.isEmpty()) {
0743         int index = instructions.indexOf(QLatin1String("}}")); // end of font defs
0744         index += 4; // skip paste }} and CR LF
0745         index = instructions.indexOf(QLatin1Char(' '), index); // find first space - end of text def
0746         index++; // and skip past it
0747                  // index should now point to the first character of the instructions
0748         instructions = instructions.remove(0, index);
0749         instructions.truncate(instructions.length() - 10);
0750     }
0751 
0752     setProperty(QStringLiteral("instructions"), instructions);
0753 
0754     char buffer[125];
0755     stream.readRawData(buffer, 25);
0756 
0757     if (strncmp(buffer, "PCStitch 6 Floss Palette!", 25) == 0) {
0758         stream >> unknown16;
0759         stream.readRawData(buffer, 40);
0760 
0761         quint16 colors;
0762         stream >> colors;
0763 
0764         readPCStitchString(stream); // symbols font
0765 
0766         stream >> unknown32;
0767 
0768         m_pattern->palette().setSchemeName(QStringLiteral("DMC"));
0769         FlossScheme *scheme = SchemeManager::scheme(QStringLiteral("DMC"));
0770 
0771         if (scheme == nullptr) {
0772             throw FailedReadFile(QString(i18n("The floss scheme DMC was not found"))); // this shouldn't happen because DMC should always be available
0773         }
0774 
0775         for (int i = 0; i < colors; i++) {
0776 #pragma pack(push)
0777 #pragma pack(1) // pack the structure
0778             struct PALETTE_ENTRY {
0779                 char colorDescription_1[30];
0780                 unsigned char RGBA[4];
0781                 char colorName_1[10];
0782                 unsigned char unknown_1[59];
0783                 unsigned short stitchStrands;
0784                 unsigned short backstitchStrands;
0785                 unsigned short unknown_2;
0786                 char colorDescription_2[30];
0787                 unsigned char unknown_3[5];
0788                 char colorName_2[25]; // seems to be Black all the time
0789             } paletteEntry;
0790 #pragma pack(pop)
0791 
0792             stream.readRawData(reinterpret_cast<char *>(&paletteEntry), sizeof(struct PALETTE_ENTRY));
0793 
0794             QColor color = QColor(paletteEntry.RGBA[0], paletteEntry.RGBA[1], paletteEntry.RGBA[2]);
0795             QString colorName = QString::fromLatin1(paletteEntry.colorName_1, 10).trimmed(); // minus the white space
0796 
0797             if (colorName == QLatin1String("White")) {
0798                 colorName = QLatin1String("Blanc"); // fix colorName
0799             }
0800 
0801             if (colorName == QLatin1String("5200")) {
0802                 colorName = QLatin1String("B5200"); // fix colorName
0803             }
0804 
0805             Floss *floss = scheme->find(colorName);
0806 
0807             if (floss == nullptr) {
0808                 floss = scheme->convert(color); // the name wasn't found so look for a similar color in DMC
0809             }
0810 
0811             colorName = floss->name();
0812             DocumentFloss *documentFloss =
0813                 new DocumentFloss(colorName, m_pattern->palette().freeSymbol(), Qt::SolidLine, paletteEntry.stitchStrands, paletteEntry.backstitchStrands);
0814             documentFloss->setFlossColor(floss->color());
0815             m_pattern->palette().add(i, documentFloss);
0816         }
0817     } else {
0818         throw FailedReadFile(QString(i18n("Invalid data read.")));
0819     }
0820 
0821     m_pattern->palette().setCurrentIndex(-1);
0822 
0823     Stitch::Type stitchType[] = {Stitch::Delete,
0824                                  Stitch::Full,
0825                                  Stitch::TL3Qtr,
0826                                  Stitch::TR3Qtr,
0827                                  Stitch::BL3Qtr,
0828                                  Stitch::BR3Qtr,
0829                                  Stitch::TBHalf,
0830                                  Stitch::BTHalf,
0831                                  Stitch::Delete,
0832                                  Stitch::TLQtr,
0833                                  Stitch::TRQtr,
0834                                  Stitch::BLQtr,
0835                                  Stitch::BRQtr}; // conversion of PCStitch to KXStitch
0836 
0837     int documentWidth = m_pattern->stitches().width();
0838     int documentHeight = m_pattern->stitches().height();
0839     int cells = documentWidth * documentHeight;
0840 
0841     quint16 cellCount;
0842 
0843     for (int i = 0; i < cells; i += cellCount) {
0844         quint8 color;
0845         quint8 type;
0846 
0847         stream >> cellCount;
0848         stream >> color;
0849         stream >> type;
0850 
0851         if (type != 0xff) {
0852             for (int c = 0; c < cellCount; c++) {
0853                 int xc = (i + c) / documentHeight;
0854                 int yc = (i + c) % documentHeight;
0855                 m_pattern->stitches().addStitch(QPoint(xc, yc), stitchType[type], color - 1); // color-1 because PCStitch uses 1 based array
0856             }
0857         }
0858     }
0859 
0860     quint32 extras;
0861     stream >> extras;
0862 
0863     while (extras--) {
0864         qint16 x;
0865         qint16 y;
0866         quint8 color;
0867         quint8 type;
0868 
0869         stream >> x;
0870         stream >> y;
0871 
0872         for (int dx = 0; dx < 4; dx++) {
0873             stream >> color;
0874             stream >> type;
0875 
0876             if (type != 0xff) {
0877                 m_pattern->stitches().addStitch(QPoint(x - 1, y - 1), stitchType[type], color - 1);
0878             }
0879         }
0880     }
0881 
0882     // read french knots
0883 
0884     quint32 knots;
0885     stream >> knots;
0886 
0887     while (knots--) {
0888         qint16 x;
0889         qint16 y;
0890         quint8 color;
0891 
0892         stream >> x;
0893         stream >> y;
0894         stream >> color;
0895         m_pattern->stitches().addFrenchKnot(QPoint(x - 1, y - 1), color - 1);
0896     }
0897 
0898     // read backstitches
0899 
0900     qint32 backstitches;
0901     stream >> backstitches;
0902 
0903     while (backstitches--) {
0904         qint16 sx;
0905         qint16 sy;
0906         qint16 sp;
0907         qint16 ex;
0908         qint16 ey;
0909         qint16 ep;
0910         quint16 color;
0911         stream >> sx >> sy >> sp >> ex >> ey >> ep >> color;
0912         m_pattern->stitches().addBackstitch(QPoint(--sx * 2 + ((sp - 1) % 3), --sy * 2 + ((sp - 1) / 3)),
0913                                             QPoint(--ex * 2 + ((ep - 1) % 3), --ey * 2 + ((ep - 1) / 3)),
0914                                             color - 1);
0915     }
0916 
0917     if (stream.status() != QDataStream::Ok) {
0918         throw FailedReadFile(QString(i18n("Stream error")));
0919     }
0920 }
0921 
0922 void Document::readPCStitch7File(QDataStream &stream)
0923 {
0924     /* File Format
0925         uchar[256]      // header 'PCStitch 7 Pattern File'
0926                         // other information is contained here
0927         uchar[4]        // unknown
0928         uchar[4]        // unknown, there is something unique to each file here
0929         quint16         // pattern width
0930         quint16         // pattern height
0931         quint16         // cloth count width
0932         quint16         // cloth count height
0933         uchar[4]        // RGBA - fabric colour
0934         quint16         // string length
0935         char[]          // author
0936         quint16         // string length
0937         char[]          // copyright
0938         quint16         // string length
0939         char[]          // title
0940         quint16         // string length
0941         char[]          // fabric
0942         quint16         // string length
0943         char[]          // instructions
0944         quint16         // string length
0945         char[]          // keywords
0946         quint16         // string length
0947         char[]          // website
0948         uchar[4]        // unknown - varies e.g. (0x02 0x00 0x02 0x00) (0x02 0x00 0x01 0x00)
0949                         // possible default stitch / backstitch strands quint16
0950         char[25]        // 'PCStitch Floss Palette!!!'
0951         uchar[4]        // unknown
0952         quint16         // palette entries
0953 
0954         [
0955             other possible entries within the header may be
0956             company
0957             logo
0958             read only flag
0959             read only password
0960             stitches/inches flag - size maybe in inches
0961             square weave flag
0962         ]
0963 
0964         struct paletteEntry {
0965             char[33]    // scheme
0966                         // palette allows for multiple schemes to be used
0967                         // keycode used to identify source list
0968             char[10]    // color name
0969             char[30]    // color description
0970             uchar[4]    // unknown
0971             uchar[4]    // RGBA
0972             uchar[81]   // unknown
0973             char[30]    // symbol font
0974             uchar[7]    // 0x00 0x00 0x42 0x00 0x00 0x00 0x00 - varies (symbols probably here, 3rd for stitches?)
0975             char[30]    // color description
0976             uchar[4]    // RGBA
0977             char[10]    // color name
0978             uchar[7]    // 0x00 0x00 0x00 0x00 0x00 0x01 0x00
0979                         // possibly stitch strands (not sure of order, 6th possibly backstitch) 0x00 for default
0980                         // Full, 3 quarter, quarter, petite, half, french, backstitches
0981         } repeated for the number of palette entries
0982 
0983         struct stitches {
0984             quint16     // stitch count in columns from top left downward
0985             quint8      // color, 1 based index of color list, 0xFF for none
0986             quint8      // stitch type, 0xFF for none
0987         } repeated until sum of stitch count = width*height
0988 
0989         uint32 extras
0990         struct extra {
0991             quint16     // x coordinate, 1 based index of cell
0992             quint16     // y coordinate, 1 based index of cell
0993             struct {
0994                 quint8  // color, 1 based index of color list, 0xFF for none
0995                 quint8  // stitch type, 0xFF for none
0996             } repeated 4 times
0997         } repeated for extras
0998 
0999         uint32 knots
1000         struct knot {
1001             quint16     // x coordinate, 1 based index of snap points
1002             quint16     // y coordinate, 1 based index of snap points
1003             quint16     // color, 1 based index of color list
1004         } repeated for knotCount
1005 
1006         uint32 backstitches
1007         struct backstitch {
1008             quint16     // start x, 1 based index of cell
1009             quint16     // start y, 1 based index of cell
1010             quint16     // start position, (1..9) based on snap points
1011             quint16     // end x, 1 based index of cell
1012             quint16     // end Y, 1 based index of cell
1013             quint16     // end position (1..9) based on snap points
1014             quint16     // color, 1 based index of color list
1015         } repeated for backstitches
1016     */
1017     stream.setByteOrder(QDataStream::LittleEndian);
1018     stream.device()->seek(256);
1019 
1020     quint32 unknown32;
1021     stream >> unknown32;
1022     stream >> unknown32;
1023 
1024     quint16 width;
1025     quint16 height;
1026     stream >> width;
1027     stream >> height;
1028 
1029     m_pattern->stitches().resize(width, height);
1030     setProperty(QStringLiteral("unitsFormat"), Configuration::EnumDocument_UnitsFormat::Stitches);
1031 
1032     quint16 clothCount;
1033     stream >> clothCount;
1034     setProperty(QStringLiteral("horizontalClothCount"), double(clothCount));
1035     stream >> clothCount;
1036     setProperty(QStringLiteral("verticalClothCount"), double(clothCount));
1037     setProperty(QStringLiteral("clothCountUnits"), Configuration::EnumEditor_ClothCountUnits::Inches);
1038 
1039     unsigned char r;
1040     unsigned char g;
1041     unsigned char b;
1042     unsigned char a;
1043     stream >> r >> g >> b >> a;
1044     setProperty(QStringLiteral("fabricColor"), QColor(r, g, b)); // alpha defaults to 255
1045     setProperty(QStringLiteral("author"), readPCStitchString(stream));
1046     setProperty(QStringLiteral("copyright"), readPCStitchString(stream));
1047     setProperty(QStringLiteral("title"), readPCStitchString(stream));
1048     setProperty(QStringLiteral("fabric"), readPCStitchString(stream));
1049 
1050     QString instructions = readPCStitchString(stream);
1051 
1052     if (!instructions.isEmpty()) {
1053         int index = instructions.indexOf(QLatin1String("}}")); // end of font defs
1054         index += 4; // skip paste }} and CR LF
1055         index = instructions.indexOf(QLatin1Char(' '), index); // find first space - end of text def
1056         index++; // and skip past it
1057                  // index should now point to the first character of the instructions
1058         instructions = instructions.remove(0, index);
1059         instructions.truncate(instructions.length() - 10);
1060     }
1061 
1062     setProperty(QStringLiteral("instructions"), instructions);
1063 
1064     QString keywords(readPCStitchString(stream));
1065     QString website(readPCStitchString(stream));
1066 
1067     quint16 defaultStitchStrands;
1068     quint16 defaultBackstitchStrands;
1069     stream >> defaultStitchStrands >> defaultBackstitchStrands;
1070 
1071     char *buffer = new char[25];
1072     stream.readRawData(buffer, 25);
1073 
1074     if (strncmp(buffer, "PCStitch Floss Palette!!!", 25) == 0) {
1075         stream >> unknown32;
1076 
1077         quint16 colors;
1078         stream >> colors;
1079 
1080         m_pattern->palette().setSchemeName(QStringLiteral("DMC"));
1081         FlossScheme *scheme = SchemeManager::scheme(QStringLiteral("DMC"));
1082 
1083         if (scheme == nullptr) {
1084             throw FailedReadFile(QString(i18n("The floss scheme DMC was not found"))); // this shouldn't happen because DMC should always be available
1085         }
1086 
1087         for (int i = 0; i < colors; i++) {
1088 #pragma pack(push)
1089 #pragma pack(1)
1090             struct PALETTE_ENTRY {
1091                 char scheme[33];
1092                 char colorName_1[10];
1093                 char colorDescription_1[30];
1094                 uchar unknown_1[4];
1095                 uchar RGBA_1[4];
1096                 uchar unknown_2[81];
1097                 char font[30];
1098                 uchar unknown_3[7];
1099                 char colorDescription_2[30];
1100                 uchar RGBA_2[4];
1101                 char colorName_2[10];
1102                 uchar unknown_4[7];
1103             } paletteEntry;
1104 #pragma pack(pop)
1105 
1106             stream.readRawData(reinterpret_cast<char *>(&paletteEntry), sizeof(struct PALETTE_ENTRY));
1107 
1108             QColor color = QColor(int(paletteEntry.RGBA_1[0]), int(paletteEntry.RGBA_1[1]), int(paletteEntry.RGBA_1[2]));
1109             QString colorName = QString::fromLatin1(paletteEntry.colorName_1, 10).trimmed(); // minus the white space
1110 
1111             if (colorName == QLatin1String("White")) {
1112                 colorName = QLatin1String("Blanc"); // fix colorName
1113             }
1114 
1115             if (colorName == QLatin1String("5200")) {
1116                 colorName = QLatin1String("B5200"); // fix colorName
1117             }
1118 
1119             Floss *floss = scheme->find(colorName);
1120 
1121             if (floss == nullptr) {
1122                 floss = scheme->convert(color); // the name wasn't found so look for a similar color in DMC
1123             }
1124 
1125             colorName = floss->name();
1126             DocumentFloss *documentFloss =
1127                 new DocumentFloss(colorName, m_pattern->palette().freeSymbol(), Qt::SolidLine, defaultStitchStrands, defaultBackstitchStrands);
1128             documentFloss->setFlossColor(floss->color());
1129             m_pattern->palette().add(i, documentFloss);
1130         }
1131     } else {
1132         throw FailedReadFile(QString(i18n("Invalid data read.")));
1133     }
1134 
1135     m_pattern->palette().setCurrentIndex(-1);
1136 
1137     Stitch::Type stitchType[] = {Stitch::Delete,
1138                                  Stitch::Full,
1139                                  Stitch::TL3Qtr,
1140                                  Stitch::TR3Qtr,
1141                                  Stitch::BL3Qtr,
1142                                  Stitch::BR3Qtr,
1143                                  Stitch::TBHalf,
1144                                  Stitch::BTHalf,
1145                                  Stitch::Delete,
1146                                  Stitch::TLQtr,
1147                                  Stitch::TRQtr,
1148                                  Stitch::BLQtr,
1149                                  Stitch::BRQtr}; // conversion of PCStitch to KXStitch
1150     // TODO above needs to include petite stitches
1151     int documentWidth = m_pattern->stitches().width();
1152     int documentHeight = m_pattern->stitches().height();
1153     int cells = documentWidth * documentHeight;
1154 
1155     quint16 cellCount;
1156 
1157     for (int i = 0; i < cells; i += cellCount) {
1158         quint8 color;
1159         quint8 type;
1160 
1161         stream >> cellCount;
1162         stream >> color;
1163         stream >> type;
1164 
1165         if (type != 0xff) {
1166             for (int c = 0; c < cellCount; c++) {
1167                 int xc = (i + c) / documentHeight;
1168                 int yc = (i + c) % documentHeight;
1169                 m_pattern->stitches().addStitch(QPoint(xc, yc), stitchType[type], color - 1); // color-1 because PCStitch uses 1 based array
1170             }
1171         }
1172     }
1173 
1174     quint32 extras;
1175     stream >> extras;
1176 
1177     while (extras--) {
1178         quint16 x;
1179         quint16 y;
1180         quint8 color;
1181         quint8 type;
1182 
1183         stream >> x;
1184         stream >> y;
1185 
1186         for (int dx = 0; dx < 4; dx++) {
1187             stream >> color;
1188             stream >> type;
1189 
1190             if (type != 0xff) {
1191                 m_pattern->stitches().addStitch(QPoint(x - 1, y - 1), stitchType[type], color - 1);
1192             }
1193         }
1194     }
1195 
1196     // read french knots
1197 
1198     quint32 knots;
1199     stream >> knots;
1200 
1201     while (knots--) {
1202         quint16 x;
1203         quint16 y;
1204         quint16 color;
1205 
1206         stream >> x;
1207         stream >> y;
1208         stream >> color;
1209         m_pattern->stitches().addFrenchKnot(QPoint(x - 1, y - 1), color - 1);
1210     }
1211 
1212     // read backstitches
1213 
1214     quint32 backstitches;
1215     stream >> backstitches;
1216 
1217     while (backstitches--) {
1218         quint16 sx;
1219         quint16 sy;
1220         quint16 sp;
1221         quint16 ex;
1222         quint16 ey;
1223         quint16 ep;
1224         quint16 color;
1225         stream >> sx >> sy >> sp >> ex >> ey >> ep >> color;
1226         m_pattern->stitches().addBackstitch(QPoint(--sx * 2 + ((sp - 1) % 3), --sy * 2 + ((sp - 1) / 3)),
1227                                             QPoint(--ex * 2 + ((ep - 1) % 3), --ey * 2 + ((ep - 1) / 3)),
1228                                             color - 1);
1229     }
1230 
1231     if (stream.status() != QDataStream::Ok) {
1232         throw FailedReadFile(QString(i18n("Stream error")));
1233     }
1234 }
1235 
1236 QString Document::readPCStitchString(QDataStream &stream)
1237 {
1238     char *buffer;
1239     quint16 stringSize;
1240     stream >> stringSize;
1241     buffer = new char[stringSize + 1];
1242     stream.readRawData(buffer, stringSize);
1243     buffer[stringSize] = '\0';
1244     QString string = QString::fromLatin1(buffer);
1245     delete[] buffer;
1246 
1247     if (stream.status() != QDataStream::Ok) {
1248         throw FailedReadFile(QString(i18n("Stream error")));
1249     }
1250 
1251     return string;
1252 }
1253 
1254 void Document::readKXStitchV2File(QDataStream &stream)
1255 {
1256     /* File format
1257         // header
1258         #QString("KXStitch")        // read in the load function
1259         #qint16(FILE_FORMAT_VERSION)    // read in the load function
1260         QString(title)
1261         QString(author)
1262         QString(fabric)
1263         QColor(fabricColor) // serialised format has changed over the various versions of qt.
1264                     // for older versions this appears to be quint8 red, quint8 green quint8 blue, quint8 alpha
1265         qint16(index from flossscheme qcombobox)    // unpredictable, palette stream will contain the scheme name
1266         qint16(inches)      // boolean, true if the size displayed is in inches
1267         qint32(width)       // width of pattern (is this in stitches or inches?) // discard in favour of stitchdata width
1268         qint32(height)      // height of pattern (is this in stitches or inches?) // discard in favour of stitchdata height
1269         qint32(clothCount)  // this needs to be converted to a double
1270         QString(instructions)
1271 
1272         // palette
1273         qint32(current)     // the current color selected
1274         qint32(colors)      // number of colors in the palette
1275         QString(schemeName)
1276             QString(flossName)      ]
1277             QString(flossDescription)   ] Repeated for each
1278             QColor(flossColor)      ] entry in the palette, note comment above regarding QColor
1279             qint16(flossSymbol)     ]
1280 
1281         // stitches
1282         qint32(width)       // width in stitches // use instead of width from the header which might be in inches
1283         qint32(height)      // height in stitches // use instead of height from the header which might be in inches
1284             qint8(stitches)                 ]
1285                 qint8(type)     ] Repeated for  ] Repeated for
1286                 qint16(colorIndex)  ] each stitch   ] each stitchqueue
1287 
1288         // backstitches
1289         qint32(backstitches)    // the number of backstitches
1290             QPoint(start)       ]
1291             QPoint(end)     ] Repeated for
1292             qint16(colorIndex)  ] each backstitch
1293 
1294         // there were no knots supported in this version
1295         */
1296 
1297     /* this is currently untested */
1298     // read header
1299     QString title;
1300     QString author;
1301     QString fabric;
1302     stream >> title >> author >> fabric;
1303     setProperty(QStringLiteral("title"), title);
1304     setProperty(QStringLiteral("author"), author);
1305     setProperty(QStringLiteral("fabric"), fabric);
1306 
1307     quint8 red;
1308     quint8 green;
1309     quint8 blue;
1310     quint8 alpha;
1311     stream >> red >> green >> blue >> alpha;
1312     setProperty(QStringLiteral("fabricColor"), QColor(red, green, blue, alpha));
1313 
1314     qint16 schemeIndex;
1315     stream >> schemeIndex; // discard
1316 
1317     qint16 inches;
1318     stream >> inches;
1319     setProperty(QStringLiteral("unitsFormat"),
1320                 (bool(inches)) ? Configuration::EnumDocument_UnitsFormat::Inches : Configuration::EnumDocument_UnitsFormat::Stitches);
1321 
1322     qint32 width;
1323     qint32 height;
1324     stream >> width >> height;
1325 
1326     qint32 clothCount;
1327     stream >> clothCount;
1328     setProperty(QStringLiteral("clothCountUnits"), Configuration::EnumEditor_ClothCountUnits::Inches);
1329     setProperty(QStringLiteral("horizontalClothCount"), double(clothCount));
1330     setProperty(QStringLiteral("verticalClothCount"), double(clothCount));
1331     setProperty(QStringLiteral("clothCountLink"), true);
1332 
1333     QString instructions;
1334     stream >> instructions;
1335     setProperty(QStringLiteral("instructions"), instructions);
1336 
1337     // read palette
1338     qint32 current;
1339     stream >> current;
1340 
1341     qint32 colors;
1342     stream >> colors;
1343 
1344     QString schemeName;
1345     stream >> schemeName;
1346     m_pattern->palette().setSchemeName(schemeName);
1347 
1348     FlossScheme *flossScheme = SchemeManager::scheme(schemeName);
1349 
1350     if (flossScheme == nullptr) {
1351         throw FailedReadFile(QString(i18n("The floss scheme %1 was not found", schemeName)));
1352     }
1353 
1354     int colorIndex = 0;
1355 
1356     while (colors--) {
1357         QString flossName;
1358         QString flossDescription;
1359         // QColor color - read as rgba instead
1360         qint16 symbol;
1361 
1362         stream >> flossName >> flossDescription >> red >> green >> blue >> alpha >> symbol;
1363 
1364         Floss *floss = flossScheme->find(flossName);
1365 
1366         if (floss == nullptr) {
1367             throw FailedReadFile(QString(i18n("The floss name %1 was not found", flossName)));
1368         }
1369 
1370         DocumentFloss *documentFloss = new DocumentFloss(flossName,
1371                                                          m_pattern->palette().freeSymbol(),
1372                                                          Qt::SolidLine,
1373                                                          Configuration::palette_StitchStrands(),
1374                                                          Configuration::palette_BackstitchStrands());
1375         documentFloss->setFlossColor(floss->color());
1376         m_pattern->palette().add(colorIndex++, documentFloss);
1377     }
1378 
1379     // read stitches
1380     stream >> width >> height;
1381     qint32 cells = width * height;
1382     m_pattern->stitches().resize(width, height);
1383 
1384     for (int i = 0; i < cells; i++) {
1385         qint8 stitches;
1386         stream >> stitches;
1387 
1388         while (stitches--) {
1389             qint8 type;
1390             qint16 colorIndex;
1391             stream >> type >> colorIndex;
1392 
1393             m_pattern->stitches().addStitch(QPoint(i % width, i / width), Stitch::Type(type), colorIndex);
1394         }
1395     }
1396 
1397     qint32 backstitches;
1398     stream >> backstitches;
1399 
1400     while (backstitches--) {
1401         QPoint start;
1402         QPoint end;
1403         qint16 colorIndex;
1404         stream >> start >> end >> colorIndex;
1405 
1406         m_pattern->stitches().addBackstitch(start, end, colorIndex);
1407     }
1408 
1409     if (stream.status() != QDataStream::Ok) {
1410         throw FailedReadFile(QString(i18n("Stream error")));
1411     }
1412 }
1413 
1414 void Document::readKXStitchV3File(QDataStream &stream)
1415 {
1416     /* File format
1417         // header
1418         #QString("KXStitch")        // read in the load function
1419         #qint16(FILE_FORMAT_VERSION)    // read in the load function
1420         QString(title)
1421         QString(author)
1422         QString(fabric)
1423         QColor(fabricColor) // serialised format has changed over the various versions of qt.
1424                     // for older versions this appears to be quint8 red, quint8 green quint8 blue, quint8 alpha
1425         qint16(index from flossscheme qcombobox)    // unpredictable, palette stream will contain the scheme name
1426         qint16(inches)      // boolean, true if the size displayed is in inches
1427         qint32(width)       // width of pattern (is this in stitches or inches?) // discard in favour of stitchdata width
1428         qint32(height)      // height of pattern (is this in stitches or inches?) // discard in favour of stitchdata height
1429         qint32(clothCount)  // this needs to be converted to a double
1430         QString(instructions)
1431 
1432         // palette
1433         QString(schemeName)
1434         qint32(current)     // the current color selected
1435         qint32(colors)      // number of colors in the palette
1436             qint32(colorIndex)      ]
1437             QString(flossName)      ] Repeated for each
1438             qint16(flossSymbol)     ] entry in the palette
1439 
1440         // stitches
1441         qint32(width)       // width in stitches // use instead of width from the header which might be in inches
1442         qint32(height)      // height in stitches // use instead of height from the header which might be in inches
1443             qint8(stitches)                 ]
1444                 qint8(type)     ] Repeated for  ] Repeated for
1445                 qint16(colorIndex)  ] each stitch   ] each stitchqueue
1446 
1447         // backstitches
1448         qint32(backstitches)    // the number of backstitches
1449             QPoint(start)       ]
1450             QPoint(end)     ] Repeated for
1451             qint16(colorIndex)  ] each backstitch
1452 
1453         // there were no knots supported in this version
1454         */
1455 
1456     /* this is currently untested */
1457     // read header
1458     QString title;
1459     QString author;
1460     QString fabric;
1461     stream >> title >> author >> fabric;
1462     setProperty(QStringLiteral("title"), title);
1463     setProperty(QStringLiteral("author"), author);
1464     setProperty(QStringLiteral("fabric"), fabric);
1465 
1466     quint8 red;
1467     quint8 green;
1468     quint8 blue;
1469     quint8 alpha;
1470     stream >> red >> green >> blue >> alpha;
1471     setProperty(QStringLiteral("fabricColor"), QColor(red, green, blue, alpha));
1472 
1473     qint16 schemeIndex;
1474     stream >> schemeIndex; // discard
1475 
1476     qint16 inches;
1477     stream >> inches;
1478     setProperty(QStringLiteral("unitsFormat"),
1479                 (bool(inches)) ? Configuration::EnumDocument_UnitsFormat::Inches : Configuration::EnumDocument_UnitsFormat::Stitches);
1480 
1481     qint32 width;
1482     qint32 height;
1483     stream >> width >> height;
1484 
1485     qint32 clothCount;
1486     stream >> clothCount;
1487     setProperty(QStringLiteral("clothCountUnits"), Configuration::EnumEditor_ClothCountUnits::Inches);
1488     setProperty(QStringLiteral("horizontalClothCount"), double(clothCount));
1489     setProperty(QStringLiteral("verticalClothCount"), double(clothCount));
1490     setProperty(QStringLiteral("clothCountLink"), true);
1491 
1492     QString instructions;
1493     stream >> instructions;
1494     setProperty(QStringLiteral("instructions"), instructions);
1495 
1496     // read palette
1497     QString schemeName;
1498     stream >> schemeName;
1499     m_pattern->palette().setSchemeName(schemeName);
1500 
1501     FlossScheme *flossScheme = SchemeManager::scheme(schemeName);
1502 
1503     if (flossScheme == nullptr) {
1504         throw FailedReadFile(QString(i18n("The floss scheme %1 was not found", schemeName)));
1505     }
1506 
1507     qint32 current;
1508     stream >> current;
1509 
1510     qint32 colors;
1511     stream >> colors;
1512 
1513     while (colors--) {
1514         qint32 colorIndex;
1515         QString flossName;
1516         qint16 symbol;
1517 
1518         stream >> colorIndex >> flossName >> symbol;
1519 
1520         Floss *floss = flossScheme->find(flossName);
1521 
1522         if (floss == nullptr) {
1523             throw FailedReadFile(QString(i18n("The floss name %1 was not found", flossName)));
1524         }
1525 
1526         DocumentFloss *documentFloss = new DocumentFloss(flossName,
1527                                                          m_pattern->palette().freeSymbol(),
1528                                                          Qt::SolidLine,
1529                                                          Configuration::palette_StitchStrands(),
1530                                                          Configuration::palette_BackstitchStrands());
1531         documentFloss->setFlossColor(floss->color());
1532         m_pattern->palette().add(colorIndex, documentFloss);
1533     }
1534 
1535     // read stitches
1536     stream >> width >> height;
1537     qint32 cells = width * height;
1538     m_pattern->stitches().resize(width, height);
1539 
1540     for (int i = 0; i < cells; i++) {
1541         qint8 stitches;
1542         stream >> stitches;
1543 
1544         while (stitches--) {
1545             qint8 type;
1546             qint16 colorIndex;
1547             stream >> type >> colorIndex;
1548 
1549             m_pattern->stitches().addStitch(QPoint(i % width, i / width), Stitch::Type(type), colorIndex);
1550         }
1551     }
1552 
1553     qint32 backstitches;
1554     stream >> backstitches;
1555 
1556     while (backstitches--) {
1557         QPoint start;
1558         QPoint end;
1559         qint16 colorIndex;
1560         stream >> start >> end >> colorIndex;
1561 
1562         m_pattern->stitches().addBackstitch(start, end, colorIndex);
1563     }
1564 
1565     if (stream.status() != QDataStream::Ok) {
1566         throw FailedReadFile(QString(i18n("Stream error")));
1567     }
1568 }
1569 
1570 void Document::readKXStitchV4File(QDataStream &stream)
1571 {
1572     // version 4 wasn't used in the release versions.
1573     // but was available in cvs
1574     /* File format
1575         // header
1576         #QString("KXStitch")        // read in the load function
1577         #qint16(FILE_FORMAT_VERSION)    // read in the load function
1578         QString(title)
1579         QString(author)
1580         QString(fabric)
1581         QColor(fabricColor) // serialised format has changed over the various versions of qt.
1582                     // for older versions this appears to be quint8 red, quint8 green quint8 blue, quint8 alpha
1583         qint16(index from flossscheme qcombobox)    // unpredictable, palette stream will contain the scheme name
1584         qint16(inches)      // boolean, true if the size displayed is in inches
1585         qint32(width)       // width of pattern (is this in stitches or inches?) // discard in favour of stitchdata width
1586         qint32(height)      // height of pattern (is this in stitches or inches?) // discard in favour of stitchdata height
1587         qint32(clothCount)  // this needs to be converted to a double
1588         QString(instructions)
1589 
1590         // palette
1591         QString(schemeName)
1592         qint32(current)     // the current color selected
1593         qint32(colors)      // number of colors in the palette
1594             qint32(colorIndex)      ]
1595             QString(flossName)      ] Repeated for each
1596             qint16(flossSymbol)     ] entry in the palette
1597 
1598         // stitches
1599         qint32(width)       // width in stitches // use instead of width from the header which might be in inches
1600         qint32(height)      // height in stitches // use instead of height from the header which might be in inches
1601             qint8(stitches)                 ]
1602                 qint8(type)     ] Repeated for  ] Repeated for
1603                 qint16(colorIndex)  ] each stitch   ] each stitchqueue
1604 
1605         // knots
1606         qint32(knots)       // the number of knots
1607             QPoint(position)    ] Repeated for
1608             qint16(colorIndex)  ] each knot
1609 
1610         // backstitches
1611         qint32(backstitches)    // the number of backstitches
1612             QPoint(start)       ]
1613             QPoint(end)     ] Repeated for
1614             qint16(colorIndex)  ] each backstitch
1615         */
1616 
1617     /* this is currently untested */
1618     // read header
1619     QString title;
1620     QString author;
1621     QString fabric;
1622     stream >> title >> author >> fabric;
1623     setProperty(QStringLiteral("title"), title);
1624     setProperty(QStringLiteral("author"), author);
1625     setProperty(QStringLiteral("fabric"), fabric);
1626 
1627     quint8 red;
1628     quint8 green;
1629     quint8 blue;
1630     quint8 alpha;
1631     stream >> red >> green >> blue >> alpha;
1632     setProperty(QStringLiteral("fabricColor"), QColor(red, green, blue, alpha));
1633 
1634     qint16 schemeIndex;
1635     stream >> schemeIndex; // discard
1636 
1637     qint16 inches;
1638     stream >> inches;
1639     setProperty(QStringLiteral("unitsFormat"),
1640                 (bool(inches)) ? Configuration::EnumDocument_UnitsFormat::Inches : Configuration::EnumDocument_UnitsFormat::Stitches);
1641 
1642     qint32 width;
1643     qint32 height;
1644     stream >> width >> height;
1645 
1646     qint32 clothCount;
1647     stream >> clothCount;
1648     setProperty(QStringLiteral("clothCountUnits"), Configuration::EnumEditor_ClothCountUnits::Inches);
1649     setProperty(QStringLiteral("horizontalClothCount"), double(clothCount));
1650     setProperty(QStringLiteral("verticalClothCount"), double(clothCount));
1651     setProperty(QStringLiteral("clothCountLink"), true);
1652 
1653     QString instructions;
1654     stream >> instructions;
1655     setProperty(QStringLiteral("instructions"), instructions);
1656 
1657     // read palette
1658     QString schemeName;
1659     stream >> schemeName;
1660     m_pattern->palette().setSchemeName(schemeName);
1661 
1662     FlossScheme *flossScheme = SchemeManager::scheme(schemeName);
1663 
1664     if (flossScheme == nullptr) {
1665         throw FailedReadFile(QString(i18n("The floss scheme %1 was not found", schemeName)));
1666     }
1667 
1668     qint32 current;
1669     stream >> current;
1670 
1671     qint32 colors;
1672     stream >> colors;
1673 
1674     while (colors--) {
1675         qint32 colorIndex;
1676         QString flossName;
1677         qint16 symbol;
1678 
1679         stream >> colorIndex >> flossName >> symbol;
1680 
1681         Floss *floss = flossScheme->find(flossName);
1682 
1683         if (floss == nullptr) {
1684             throw FailedReadFile(QString(i18n("The floss name %1 was not found", flossName)));
1685         }
1686 
1687         DocumentFloss *documentFloss = new DocumentFloss(flossName,
1688                                                          m_pattern->palette().freeSymbol(),
1689                                                          Qt::SolidLine,
1690                                                          Configuration::palette_StitchStrands(),
1691                                                          Configuration::palette_BackstitchStrands());
1692         documentFloss->setFlossColor(floss->color());
1693         m_pattern->palette().add(colorIndex, documentFloss);
1694     }
1695 
1696     // read stitches
1697     stream >> width >> height;
1698     qint32 cells = width * height;
1699     m_pattern->stitches().resize(width, height);
1700 
1701     for (int i = 0; i < cells; i++) {
1702         qint8 stitches;
1703         stream >> stitches;
1704 
1705         while (stitches--) {
1706             qint8 type;
1707             qint16 colorIndex;
1708             stream >> type >> colorIndex;
1709 
1710             m_pattern->stitches().addStitch(QPoint(i % width, i / width), Stitch::Type(type), colorIndex);
1711         }
1712     }
1713 
1714     qint32 knots;
1715     stream >> knots;
1716 
1717     while (knots--) {
1718         QPoint position;
1719         qint16 colorIndex;
1720         stream >> position >> colorIndex;
1721 
1722         m_pattern->stitches().addFrenchKnot(position, colorIndex);
1723     }
1724 
1725     qint32 backstitches;
1726     stream >> backstitches;
1727 
1728     while (backstitches--) {
1729         QPoint start;
1730         QPoint end;
1731         qint16 colorIndex;
1732         stream >> start >> end >> colorIndex;
1733 
1734         m_pattern->stitches().addBackstitch(start, end, colorIndex);
1735     }
1736 
1737     if (stream.status() != QDataStream::Ok) {
1738         throw FailedReadFile(QString(i18n("Stream error")));
1739     }
1740 }
1741 
1742 void Document::readKXStitchV5File(QDataStream &stream)
1743 {
1744     /* File format
1745         // header
1746         #QString("KXStitch")        // read in the load function
1747         #qint16(FILE_FORMAT_VERSION)    // read in the load function
1748 
1749         // properties dialog
1750         QString(sizeUnits)
1751         qint32(width)       // this is in stitches
1752         qint32(height)      // this is in stitches
1753         double(clothCount)
1754         QString(clothCountUnits)
1755         QString(title)
1756         QString(author)
1757         QString(copyright)
1758         QString(fabric)
1759         QColor(fabricColor) // serialised format has changed over the various versions of qt.
1760                     // for older versions this appears to be quint8 red, quint8 green quint8 blue, quint8 alpha
1761         QString(schemeName)
1762         QString(instructions)
1763 
1764         // palette
1765         QString(schemeName)
1766         qint32(current)     // the current color selected
1767         qint32(colors)      // number of colors in the palette
1768             qint32(colorIndex)      ]
1769             QString(flossName)      ] Repeated for each
1770             qint16(flossSymbol)     ] entry in the palette
1771 
1772         // stitches
1773         qint32(width)       // width in stitches // use instead of width from the header which might be in inches
1774         qint32(height)      // height in stitches // use instead of height from the header which might be in inches
1775             qint8(stitches)                 ]
1776                 qint8(type)     ] Repeated for  ] Repeated for
1777                 qint16(colorIndex)  ] each stitch   ] each stitchqueue
1778 
1779         // knots
1780         qint32(knots)       // the number of knots
1781             QPoint(position)    ] Repeated for
1782             qint16(colorIndex)  ] each knot
1783 
1784         // backstitches
1785         qint32(backstitches)    // the number of backstitches
1786             QPoint(start)       ]
1787             QPoint(end)     ] Repeated for
1788             qint16(colorIndex)  ] each backstitch
1789         */
1790 
1791     /* this is currently untested */
1792     // read header
1793     QString sizeUnits;
1794     qint32 width;
1795     qint32 height;
1796     stream >> sizeUnits >> width >> height;
1797 
1798     if (sizeUnits == i18n("Stitches")) {
1799         setProperty(QStringLiteral("unitsFormat"), Configuration::EnumDocument_UnitsFormat::Stitches);
1800     }
1801 
1802     if (sizeUnits == i18n("CM")) {
1803         setProperty(QStringLiteral("unitsFormat"), Configuration::EnumDocument_UnitsFormat::Centimeters);
1804     }
1805 
1806     if (sizeUnits == i18n("Inches")) {
1807         setProperty(QStringLiteral("unitsFormat"), Configuration::EnumDocument_UnitsFormat::Inches);
1808     }
1809 
1810     double clothCount;
1811     QString clothCountUnits;
1812     stream >> clothCount >> clothCountUnits;
1813     setProperty(QStringLiteral("horizontalClothCount"), double(clothCount));
1814     setProperty(QStringLiteral("verticalClothCount"), double(clothCount));
1815     setProperty(QStringLiteral("clothCountLink"), true);
1816 
1817     if (clothCountUnits == QLatin1String("/cm")) {
1818         setProperty(QStringLiteral("clothCountUnits"), Configuration::EnumEditor_ClothCountUnits::Centimeters);
1819     }
1820 
1821     if (clothCountUnits == QLatin1String("/in")) {
1822         setProperty(QStringLiteral("clothCountUnits"), Configuration::EnumEditor_ClothCountUnits::Inches);
1823     }
1824 
1825     QString title;
1826     QString author;
1827     QString copyright;
1828     QString fabric;
1829     stream >> title >> author >> copyright >> fabric;
1830     setProperty(QStringLiteral("title"), title);
1831     setProperty(QStringLiteral("author"), author);
1832     setProperty(QStringLiteral("copyright"), copyright);
1833     setProperty(QStringLiteral("fabric"), fabric);
1834 
1835     quint8 red;
1836     quint8 green;
1837     quint8 blue;
1838     quint8 alpha;
1839     stream >> red >> green >> blue >> alpha;
1840     setProperty(QStringLiteral("fabricColor"), QColor(red, green, blue, alpha));
1841 
1842     QString schemeName;
1843     stream >> schemeName; // discard, also read in palette
1844 
1845     QString instructions;
1846     stream >> instructions;
1847     setProperty(QStringLiteral("instructions"), instructions);
1848 
1849     // read palette
1850     stream >> schemeName;
1851     m_pattern->palette().setSchemeName(schemeName);
1852 
1853     FlossScheme *flossScheme = SchemeManager::scheme(schemeName);
1854 
1855     if (flossScheme == nullptr) {
1856         throw FailedReadFile(QString(i18n("The floss scheme %1 was not found", schemeName)));
1857     }
1858 
1859     qint32 current;
1860     stream >> current;
1861 
1862     qint32 colors;
1863     stream >> colors;
1864 
1865     while (colors--) {
1866         qint32 colorIndex;
1867         QString flossName;
1868         qint16 symbol;
1869 
1870         stream >> colorIndex >> flossName >> symbol;
1871 
1872         Floss *floss = flossScheme->find(flossName);
1873 
1874         if (floss == nullptr) {
1875             throw FailedReadFile(QString(i18n("The floss name %1 was not found", flossName)));
1876         }
1877 
1878         DocumentFloss *documentFloss = new DocumentFloss(flossName,
1879                                                          m_pattern->palette().freeSymbol(),
1880                                                          Qt::SolidLine,
1881                                                          Configuration::palette_StitchStrands(),
1882                                                          Configuration::palette_BackstitchStrands());
1883         documentFloss->setFlossColor(floss->color());
1884         m_pattern->palette().add(colorIndex, documentFloss);
1885     }
1886 
1887     // read stitches
1888     stream >> width >> height;
1889     qint32 cells = width * height;
1890     m_pattern->stitches().resize(width, height);
1891 
1892     for (int i = 0; i < cells; i++) {
1893         qint8 stitches;
1894         stream >> stitches;
1895 
1896         while (stitches--) {
1897             qint8 type;
1898             qint16 colorIndex;
1899             stream >> type >> colorIndex;
1900 
1901             m_pattern->stitches().addStitch(QPoint(i % width, i / width), Stitch::Type(type), colorIndex);
1902         }
1903     }
1904 
1905     qint32 knots;
1906     stream >> knots;
1907 
1908     while (knots--) {
1909         QPoint position;
1910         qint16 colorIndex;
1911         stream >> position >> colorIndex;
1912 
1913         m_pattern->stitches().addFrenchKnot(position, colorIndex);
1914     }
1915 
1916     qint32 backstitches;
1917     stream >> backstitches;
1918 
1919     while (backstitches--) {
1920         QPoint start;
1921         QPoint end;
1922         qint16 colorIndex;
1923         stream >> start >> end >> colorIndex;
1924 
1925         m_pattern->stitches().addBackstitch(start, end, colorIndex);
1926     }
1927 
1928     if (stream.status() != QDataStream::Ok) {
1929         throw FailedReadFile(QString(i18n("Stream error")));
1930     }
1931 }
1932 
1933 void Document::readKXStitchV6File(QDataStream &stream)
1934 {
1935     /* File format
1936         // header
1937         #QString("KXStitch")        // read in the load function
1938         #qint16(FILE_FORMAT_VERSION)    // read in the load function
1939 
1940         // properties dialog
1941         QString(sizeUnits)
1942         qint32(width)       // this is in stitches
1943         qint32(height)      // this is in stitches
1944         double(clothCount)
1945         QString(clothCountUnits)
1946         QString(title)
1947         QString(author)
1948         QString(copyright)
1949         QString(fabric)
1950         QColor(fabricColor) // serialised format has changed over the various versions of qt.
1951                     // for older versions this appears to be quint8 red, quint8 green quint8 blue, quint8 alpha
1952         QString(schemeName)
1953         QString(instructions)
1954 
1955         // palette
1956         QString(schemeName)
1957         qint32(current)     // the current color selected
1958         qint32(colors)      // number of colors in the palette
1959             qint32(colorIndex)      ]
1960             QString(flossName)      ] Repeated for each
1961             qint16(flossSymbol)     ] entry in the palette
1962             qint8(stitchStrands)        ]
1963             qint8(backstitchStrands)    ]
1964 
1965         // stitches
1966         qint32(width)       // width in stitches // use instead of width from the header which might be in inches
1967         qint32(height)      // height in stitches // use instead of height from the header which might be in inches
1968             qint8(stitches)                 ]
1969                 qint8(type)     ] Repeated for  ] Repeated for
1970                 qint16(colorIndex)  ] each stitch   ] each stitchqueue
1971 
1972         // knots
1973         qint32(knots)       // the number of knots
1974             QPoint(position)    ] Repeated for
1975             qint16(colorIndex)  ] each knot
1976 
1977         // backstitches
1978         qint32(backstitches)    // the number of backstitches
1979             QPoint(start)       ]
1980             QPoint(end)     ] Repeated for
1981             qint16(colorIndex)  ] each backstitch
1982         */
1983 
1984     /* Working */
1985     // read header
1986     QString sizeUnits;
1987     qint32 width;
1988     qint32 height;
1989     stream >> sizeUnits >> width >> height;
1990 
1991     if (sizeUnits == i18n("Stitches")) {
1992         setProperty(QStringLiteral("unitsFormat"), Configuration::EnumDocument_UnitsFormat::Stitches);
1993     }
1994 
1995     if (sizeUnits == i18n("CM")) {
1996         setProperty(QStringLiteral("unitsFormat"), Configuration::EnumDocument_UnitsFormat::Centimeters);
1997     }
1998 
1999     if (sizeUnits == i18n("Inches")) {
2000         setProperty(QStringLiteral("unitsFormat"), Configuration::EnumDocument_UnitsFormat::Inches);
2001     }
2002 
2003     double clothCount;
2004     QString clothCountUnits;
2005     stream >> clothCount >> clothCountUnits;
2006     setProperty(QStringLiteral("horizontalClothCount"), double(clothCount));
2007     setProperty(QStringLiteral("verticalClothCount"), double(clothCount));
2008     setProperty(QStringLiteral("clothCountLink"), true);
2009 
2010     if (clothCountUnits == QLatin1String("/cm")) {
2011         setProperty(QStringLiteral("clothCountUnits"), Configuration::EnumEditor_ClothCountUnits::Centimeters);
2012     }
2013 
2014     if (clothCountUnits == QLatin1String("/in")) {
2015         setProperty(QStringLiteral("clothCountUnits"), Configuration::EnumEditor_ClothCountUnits::Inches);
2016     }
2017 
2018     QString title;
2019     QString author;
2020     QString copyright;
2021     QString fabric;
2022     stream >> title >> author >> copyright >> fabric;
2023     setProperty(QStringLiteral("title"), title);
2024     setProperty(QStringLiteral("author"), author);
2025     setProperty(QStringLiteral("copyright"), copyright);
2026     setProperty(QStringLiteral("fabric"), fabric);
2027 
2028     quint8 red;
2029     quint8 green;
2030     quint8 blue;
2031     quint8 alpha;
2032     stream >> red >> green >> blue >> alpha;
2033     setProperty(QStringLiteral("fabricColor"), QColor(red, green, blue, alpha));
2034 
2035     QString schemeName;
2036     stream >> schemeName; // discard, also read in palette
2037 
2038     QString instructions;
2039     stream >> instructions;
2040     setProperty(QStringLiteral("instructions"), instructions);
2041 
2042     // read palette
2043     stream >> schemeName;
2044     m_pattern->palette().setSchemeName(schemeName);
2045 
2046     FlossScheme *flossScheme = SchemeManager::scheme(schemeName);
2047 
2048     if (flossScheme == nullptr) {
2049         throw FailedReadFile(QString(i18n("The floss scheme %1 was not found", schemeName)));
2050     }
2051 
2052     qint32 current;
2053     stream >> current;
2054 
2055     qint32 colors;
2056     stream >> colors;
2057 
2058     while (colors--) {
2059         qint32 colorIndex;
2060         QString flossName;
2061         qint16 symbol;
2062         qint8 stitchStrands;
2063         qint8 backstitchStrands;
2064 
2065         stream >> colorIndex >> flossName >> symbol >> stitchStrands >> backstitchStrands;
2066 
2067         Floss *floss = flossScheme->find(flossName);
2068 
2069         if (floss == nullptr) {
2070             throw FailedReadFile(QString(i18n("The floss name %1 was not found", flossName)));
2071         }
2072 
2073         DocumentFloss *documentFloss = new DocumentFloss(flossName, m_pattern->palette().freeSymbol(), Qt::SolidLine, stitchStrands, backstitchStrands);
2074         documentFloss->setFlossColor(floss->color());
2075         m_pattern->palette().add(colorIndex, documentFloss);
2076     }
2077 
2078     // read stitches
2079     stream >> width >> height;
2080     qint32 cells = width * height;
2081     m_pattern->stitches().resize(width, height);
2082 
2083     for (int i = 0; i < cells; i++) {
2084         qint8 stitches;
2085         stream >> stitches;
2086 
2087         while (stitches--) {
2088             qint8 type;
2089             qint16 colorIndex;
2090             stream >> type >> colorIndex;
2091 
2092             m_pattern->stitches().addStitch(QPoint(i % width, i / width), Stitch::Type(type), colorIndex);
2093         }
2094     }
2095 
2096     qint32 knots;
2097     stream >> knots;
2098 
2099     while (knots--) {
2100         QPoint position;
2101         qint16 colorIndex;
2102         stream >> position >> colorIndex;
2103 
2104         m_pattern->stitches().addFrenchKnot(position, colorIndex);
2105     }
2106 
2107     qint32 backstitches;
2108     stream >> backstitches;
2109 
2110     while (backstitches--) {
2111         QPoint start;
2112         QPoint end;
2113         qint16 colorIndex;
2114         stream >> start >> end >> colorIndex;
2115 
2116         m_pattern->stitches().addBackstitch(start, end, colorIndex);
2117     }
2118 
2119     if (stream.status() != QDataStream::Ok) {
2120         throw FailedReadFile(QString(i18n("Stream error")));
2121     }
2122 }
2123 
2124 void Document::readKXStitchV7File(QDataStream &stream)
2125 {
2126     /* File format
2127         // header
2128         #QString("KXStitch")        // read in the load function
2129         #qint16(FILE_FORMAT_VERSION)    // read in the load function
2130 
2131         // properties dialog
2132         qint32(sizeUnits)
2133         qint32(width)       // this is in stitches
2134         qint32(height)      // this is in stitches
2135         double(clothCount)
2136         qint32(clothCountUnits)
2137         QString(title)
2138         QString(author)
2139         QString(copyright)
2140         QString(fabric)
2141         QColor(fabricColor) // serialised format has changed over the various versions of qt.
2142                     // for older versions this appears to be quint8 red, quint8 green quint8 blue, quint8 alpha
2143         QString(schemeName)
2144         QString(instructions)
2145 
2146         // palette
2147         QString(schemeName)
2148         qint32(current)     // the current color selected
2149         qint32(colors)      // number of colors in the palette
2150             qint32(colorIndex)      ]
2151             QString(flossName)      ] Repeated for each
2152             qint16(flossSymbol)     ] entry in the palette
2153             qint8(stitchStrands)        ]
2154             qint8(backstitchStrands)    ]
2155 
2156         // stitches
2157         qint32(width)       // width in stitches // use instead of width from the header which might be in inches
2158         qint32(height)      // height in stitches // use instead of height from the header which might be in inches
2159             qint8(stitches)                 ]
2160                 qint8(type)     ] Repeated for  ] Repeated for
2161                 qint16(colorIndex)  ] each stitch   ] each stitchqueue
2162 
2163         // knots
2164         qint32(knots)       // the number of knots
2165             QPoint(position)    ] Repeated for
2166             qint16(colorIndex)  ] each knot
2167 
2168         // backstitches
2169         qint32(backstitches)    // the number of backstitches
2170             QPoint(start)       ]
2171             QPoint(end)     ] Repeated for
2172             qint16(colorIndex)  ] each backstitch
2173         */
2174 
2175     /* Working */
2176     Configuration::EnumDocument_UnitsFormat::type convertSizeUnits[] = {Configuration::EnumDocument_UnitsFormat::Stitches,
2177                                                                         Configuration::EnumDocument_UnitsFormat::Centimeters, // was MM
2178                                                                         Configuration::EnumDocument_UnitsFormat::Centimeters,
2179                                                                         Configuration::EnumDocument_UnitsFormat::Inches};
2180     Configuration::EnumEditor_ClothCountUnits::type convertClothCountUnits[] = {Configuration::EnumEditor_ClothCountUnits::Inches, // was Stitches
2181                                                                                 Configuration::EnumEditor_ClothCountUnits::Centimeters,
2182                                                                                 Configuration::EnumEditor_ClothCountUnits::Inches};
2183     // read header
2184     qint32 sizeUnits;
2185     qint32 width;
2186     qint32 height;
2187     stream >> sizeUnits >> width >> height;
2188     setProperty(QStringLiteral("unitsFormat"), convertSizeUnits[sizeUnits]);
2189 
2190     double clothCount;
2191     qint32 clothCountUnits;
2192     stream >> clothCount >> clothCountUnits;
2193     setProperty(QStringLiteral("horizontalClothCount"), double(clothCount));
2194     setProperty(QStringLiteral("verticalClothCount"), double(clothCount));
2195     setProperty(QStringLiteral("clothCountLink"), true);
2196     setProperty(QStringLiteral("clothCountUnits"), convertClothCountUnits[clothCountUnits]);
2197 
2198     QString title;
2199     QString author;
2200     QString copyright;
2201     QString fabric;
2202     stream >> title >> author >> copyright >> fabric;
2203     setProperty(QStringLiteral("title"), title);
2204     setProperty(QStringLiteral("author"), author);
2205     setProperty(QStringLiteral("copyright"), copyright);
2206     setProperty(QStringLiteral("fabric"), fabric);
2207 
2208     quint8 red;
2209     quint8 green;
2210     quint8 blue;
2211     quint8 alpha;
2212     stream >> red >> green >> blue >> alpha;
2213     setProperty(QStringLiteral("fabricColor"), QColor(red, green, blue, alpha));
2214 
2215     QString schemeName;
2216     stream >> schemeName; // discard, also read in palette
2217 
2218     QString instructions;
2219     stream >> instructions;
2220     setProperty(QStringLiteral("instructions"), instructions);
2221 
2222     // read palette
2223     stream >> schemeName;
2224     m_pattern->palette().setSchemeName(schemeName);
2225 
2226     FlossScheme *flossScheme = SchemeManager::scheme(schemeName);
2227 
2228     if (flossScheme == nullptr) {
2229         throw FailedReadFile(QString(i18n("The floss scheme %1 was not found", schemeName)));
2230     }
2231 
2232     qint32 current;
2233     stream >> current;
2234 
2235     qint32 colors;
2236     stream >> colors;
2237 
2238     while (colors--) {
2239         qint32 colorIndex;
2240         QString flossName;
2241         qint16 symbol;
2242         qint8 stitchStrands;
2243         qint8 backstitchStrands;
2244 
2245         stream >> colorIndex >> flossName >> symbol >> stitchStrands >> backstitchStrands;
2246 
2247         Floss *floss = flossScheme->find(flossName);
2248 
2249         if (floss == nullptr) {
2250             throw FailedReadFile(QString(i18n("The floss name %1 was not found", flossName)));
2251         }
2252 
2253         DocumentFloss *documentFloss = new DocumentFloss(flossName, m_pattern->palette().freeSymbol(), Qt::SolidLine, stitchStrands, backstitchStrands);
2254         documentFloss->setFlossColor(floss->color());
2255         m_pattern->palette().add(colorIndex, documentFloss);
2256     }
2257 
2258     // read stitches
2259     stream >> width >> height;
2260     qint32 cells = width * height;
2261     m_pattern->stitches().resize(width, height);
2262 
2263     for (int i = 0; i < cells; i++) {
2264         qint8 stitches;
2265         stream >> stitches;
2266 
2267         while (stitches--) {
2268             qint8 type;
2269             qint16 colorIndex;
2270             stream >> type >> colorIndex;
2271 
2272             m_pattern->stitches().addStitch(QPoint(i % width, i / width), Stitch::Type(type), colorIndex);
2273         }
2274     }
2275 
2276     qint32 knots;
2277     stream >> knots;
2278 
2279     while (knots--) {
2280         QPoint position;
2281         qint16 colorIndex;
2282         stream >> position >> colorIndex;
2283 
2284         m_pattern->stitches().addFrenchKnot(position, colorIndex);
2285     }
2286 
2287     qint32 backstitches;
2288     stream >> backstitches;
2289 
2290     while (backstitches--) {
2291         QPoint start;
2292         QPoint end;
2293         qint16 colorIndex;
2294         stream >> start >> end >> colorIndex;
2295 
2296         m_pattern->stitches().addBackstitch(start, end, colorIndex);
2297     }
2298 
2299     if (stream.status() != QDataStream::Ok) {
2300         throw FailedReadFile(QString(i18n("Stream error")));
2301     }
2302 }