File indexing completed on 2024-07-14 07:17:19

0001 /*
0002     SPDX-FileCopyrightText: 2018 Valentin Boettcher <valentin@boettcher.cf>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #pragma once
0008 
0009 #include <QDataStream>
0010 #include <QDebug>
0011 
0012 #include "listcomponent.h"
0013 #include "binarylistcomponent.h"
0014 #include "auxiliary/kspaths.h"
0015 
0016 //TODO: Error Handling - SERIOUSLY
0017 
0018 /**
0019  * @class BinaryListComponent
0020  * @short provides functionality for loading the component data from Binary
0021  * @author Valentin Boettcher
0022  * @version 1.0
0023  *
0024  * This class is an abstract Template which requires that the type `T` is some child of
0025  * `SkyObject` and the type `Component` is some child of `ListComponent`. The class `T`
0026  * must provide a static `TYPE` property of the type `SkyObject::TYPE`. This is required
0027  * because access to the `type()` method is inconvenient here!
0028  *
0029  * The derived class must provide a `void loadFromText()` method, which loads the component
0030  * via `addListObject` or similar. (This method implements parsing etc, and cannot be
0031  * abstracted by this class.)
0032  *
0033  * Finally, one has to add this template as a friend class upon deriving it.
0034  * This is a concession to the already present architecture.
0035  *
0036  * File paths are determent by the means of KSPaths::writableLocation.
0037  */
0038 template <class T, typename Component>
0039 class BinaryListComponent
0040 {
0041 public:
0042     /**
0043      * @brief BinaryListComponent
0044      * @param parent a reference to the inheriting child
0045      * @param basename the base filename for the binary
0046      *
0047      * Sets the file extensions to `dat` for text and `bin` for binary.
0048      */
0049     BinaryListComponent(Component* parent, QString basename);
0050 
0051     /**
0052      * @brief BinaryListComponent
0053      * @param parent a reference to the inheriting child
0054      * @param basename the base filename for the binary
0055      * @param txtExt text data file extension
0056      * @param binExt binary data file extension
0057      */
0058     BinaryListComponent(Component* parent, QString basename, QString txtExt, QString binExt);
0059 
0060 protected:
0061     /**
0062      * @brief loadData
0063      * @short Calls `loadData(false)`
0064      */
0065     virtual void loadData();
0066 
0067     /**
0068      * @brief loadData
0069      * @short Load the component data from binary (if available) or from text
0070      * @param dropBinaryFile whether to drop the current binary (and to recreate it)
0071      *
0072      * Tip: If you want to reload the data and recreate the binfile, just call
0073      * loadData(true).
0074      */
0075     virtual void loadData(bool dropBinaryFile);
0076 
0077     /**
0078      * @brief loadDataFromBinary
0079      * @short Opens the default binfile and calls `loadDataFromBinary([FILE])`
0080      */
0081     virtual void loadDataFromBinary();
0082 
0083     /**
0084      * @brief loadDataFromBinary
0085      * @param binfile the binary file
0086      * @short Loads the component data from the given binary.
0087      */
0088     virtual void loadDataFromBinary(QFile &binfile);
0089 
0090     /**
0091      * @brief writeBinary
0092      * @short Opens the default binfile and calls `writeBinary([FILE])`
0093      */
0094     virtual void writeBinary();
0095 
0096     /**
0097      * @brief writeBinary
0098      * @param binfile
0099      * @short Writes the component data to the specified binary. (Destructive)
0100      */
0101     virtual void writeBinary(QFile &binfile);
0102 
0103     /**
0104      * @brief loadDataFromText
0105      * @short Load the component data from text.
0106      *
0107      * This method shall be implemented by those who derive this class.
0108      *
0109      * This method should load the component data from text by the use of
0110      * `addListObject`  or similar.
0111      */
0112     virtual void loadDataFromText() = 0;
0113 
0114     // TODO: Rename, and integrate it into a wrapper
0115     //virtual void updateDataFile() = 0; // legacy from current implementation!
0116 
0117     /**
0118      * @brief dropBinary
0119      * @short Removes the binary file.
0120      * @return True if operation succeeds
0121      */
0122     virtual bool dropBinary();
0123 
0124     /**
0125      * @brief dropText
0126      * @short Removes the text file.
0127      * @return True if operation succeeds
0128      */
0129     virtual bool dropText();
0130 
0131     /**
0132      * @brief clearData
0133      * @short Removes the current component data where necessary.
0134      */
0135     virtual void clearData();
0136 
0137     QString filepath_txt;
0138     QString filepath_bin;
0139 
0140 // Don't allow the children to mess with the Binary Version!
0141 private:
0142     QDataStream::Version binversion = QDataStream::Qt_5_5;
0143     Component* parent;
0144 };
0145 
0146 template<class T, typename Component>
0147  BinaryListComponent<T, Component>::BinaryListComponent(Component *parent, QString basename) :  BinaryListComponent<T, Component>(parent, basename, "dat", "bin") {}
0148 
0149 template<class T, typename Component>
0150  BinaryListComponent<T, Component>::BinaryListComponent(Component *parent, QString basename, QString txtExt, QString binExt) : parent { parent }
0151 {
0152      filepath_bin = QDir(KSPaths::writableLocation(QStandardPaths::AppLocalDataLocation)).filePath(basename + '.' + binExt);
0153      filepath_txt = QDir(KSPaths::writableLocation(QStandardPaths::AppLocalDataLocation)).filePath(basename + '.' + txtExt);
0154 }
0155 
0156 template<class T, typename Component>
0157 void  BinaryListComponent<T, Component>::loadData()
0158 {
0159     loadData(false);
0160 }
0161 
0162 template<class T, typename Component>
0163 void  BinaryListComponent<T, Component>::loadData(bool dropBinaryFile)
0164 {
0165     // Clear old Stuff (in case of reload)
0166     clearData();
0167 
0168     // Drop Binary file for a fresh reload
0169     if(dropBinaryFile)
0170         dropBinary();
0171 
0172     QFile binfile(filepath_bin);
0173     if (binfile.exists()) {
0174         loadDataFromBinary(binfile);
0175     } else {
0176         loadDataFromText();
0177         writeBinary(binfile);
0178     }
0179 }
0180 
0181 template<class T, typename Component>
0182 void  BinaryListComponent<T, Component>::loadDataFromBinary()
0183 {
0184     QFile binfile(filepath_bin);
0185     loadDataFromBinary(binfile);
0186 }
0187 
0188 template<class T, typename Component>
0189 void  BinaryListComponent<T, Component>::loadDataFromBinary(QFile &binfile)
0190 {
0191     // Open our binary file and create a Stream
0192     if (binfile.open(QIODevice::ReadOnly))
0193     {
0194         QDataStream in(&binfile);
0195 
0196         // Use the specified binary version
0197         // TODO: Place this into the config
0198         in.setVersion(binversion);
0199         in.setFloatingPointPrecision(QDataStream::DoublePrecision);
0200 
0201         while(!in.atEnd()){
0202             T *new_object = nullptr;
0203             in >> new_object;
0204 
0205             parent->appendListObject(new_object);
0206             // Add name to the list of object names
0207             parent->objectNames(T::TYPE).append(new_object->name());
0208             parent->objectLists(T::TYPE).append(QPair<QString, const SkyObject *>(new_object->name(), new_object));
0209         }
0210         binfile.close();
0211     }
0212     else qWarning() << "Failed loading binary data from" << binfile.fileName();
0213 }
0214 
0215 template<class T, typename Component>
0216 void  BinaryListComponent<T, Component>::writeBinary()
0217 {
0218     QFile binfile(filepath_bin);
0219     writeBinary(binfile);
0220 }
0221 
0222 template<class T, typename Component>
0223 void  BinaryListComponent<T, Component>::writeBinary(QFile &binfile)
0224 {
0225     // Open our file and create a stream
0226     binfile.open(QIODevice::WriteOnly | QIODevice::Truncate);
0227     QDataStream out(&binfile);
0228     out.setVersion(binversion);
0229     out.setFloatingPointPrecision(QDataStream::DoublePrecision);
0230 
0231     // Now just dump out everything
0232     for(auto object : parent->m_ObjectList){
0233          out << *((T*)object);
0234     }
0235 
0236     binfile.close();
0237 }
0238 
0239 template<class T, typename Component>
0240 bool  BinaryListComponent<T, Component>::dropBinary()
0241 {
0242     return QFile::remove(filepath_bin);
0243 }
0244 
0245 template<class T, typename Component>
0246 bool  BinaryListComponent<T, Component>::dropText()
0247 {
0248     return QFile::remove(filepath_txt);
0249 }
0250 
0251 template<class T, typename Component>
0252 void  BinaryListComponent<T, Component>::clearData()
0253 {
0254     // Clear lists
0255     qDeleteAll(parent->m_ObjectList);
0256     parent->m_ObjectList.clear();
0257     parent->m_ObjectHash.clear();
0258 
0259     parent->objectLists(T::TYPE).clear();
0260     parent->objectNames(T::TYPE).clear();
0261 }