File indexing completed on 2025-01-19 09:45:57
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 }