File indexing completed on 2024-05-05 08:41:23
0001 /* 0002 * Copyright (C) 2011-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 /** 0012 * @file 0013 * Implement the SymbolLibrary class 0014 */ 0015 0016 /** 0017 * @page symbol_library Symbol Library 0018 * The symbols created are stored in symbol files. A number of different files can be created containing symbols 0019 * of different themes. When files are opened the symbol library will be populated with the contents of the file. 0020 * 0021 * The symbol library can be associated with a LibraryListWidget which will provide an icon view of all the 0022 * existing symbols. Clicking on one of the icons will open this symbol in the editor and allow it to be modified. 0023 * New symbols created can be saved to the library. 0024 * 0025 * Note that symbols saved to the library are not immediately saved to disk. The user is required to save the 0026 * library with the File->Save command. The user may also use the File->Save As command to save the library to a 0027 * different file. 0028 * 0029 * @image html ui-main-library.png "The user interface showing the library tab" 0030 * 0031 * All changes to the library through adding new symbols, editing a symbol or importing a library can be undone 0032 * or redone with the undo and redo commands. A separate undo stack is managed for the library and for the editor 0033 * and the active one is dependent on which of the tabs is selected. Undoing commands in the editor tab does not 0034 * affect the library, similarly undoing commands in the library does not affect the editor. 0035 * 0036 * A context menu is available for the symbols in the list allowing individual symbols to be deleted. This can be 0037 * undone if required. 0038 * 0039 * Using the File->Import Library it is also possible to import symbols from another symbol file into the current 0040 * symbol library. These will then be appended to the current set of symbols. 0041 * 0042 * File->Close will close the current library leaving a new empty library that new symbols can be added to. 0043 */ 0044 0045 #include "SymbolLibrary.h" 0046 0047 #include <QDataStream> 0048 #include <QListWidget> 0049 #include <QListWidgetItem> 0050 #include <QPainter> 0051 0052 #include <KLocalizedString> 0053 0054 #include "Exceptions.h" 0055 #include "SymbolListWidget.h" 0056 0057 /** 0058 * Construct a SymbolLibrary. 0059 * Set the url to Untitled and the index to 1. 0060 * The index will be set when a file is loaded and will be incremented when new symbols 0061 * have been added. It will be saved with the file for the next time it is loaded. 0062 */ 0063 SymbolLibrary::SymbolLibrary(SymbolListWidget *listWidget) 0064 : m_listWidget(listWidget) 0065 { 0066 clear(); 0067 } 0068 0069 /** 0070 * Destructor 0071 */ 0072 SymbolLibrary::~SymbolLibrary() 0073 { 0074 clear(); 0075 } 0076 0077 /** 0078 * Clear the file of symbols. 0079 * Clears the undo stack, deletes all the QListWidgetItems and clears the symbol map. 0080 * The index is reset to 1. 0081 * The url is initialized to Untitled 0082 */ 0083 void SymbolLibrary::clear() 0084 { 0085 m_undoStack.clear(); 0086 0087 if (m_listWidget) { 0088 foreach (qint16 index, indexes()) { 0089 m_listWidget->removeSymbol(index); 0090 } 0091 } 0092 0093 m_symbols.clear(); 0094 m_nextIndex = 1; 0095 m_url = QUrl(i18n("Untitled")); 0096 } 0097 0098 /** 0099 * Get the path associated with an index. 0100 * If the index is not in the library it returns a default constructed Symbol. 0101 * 0102 * @param index a qint16 representing the index to find 0103 * 0104 * @return a Symbol 0105 */ 0106 Symbol SymbolLibrary::symbol(qint16 index) const 0107 { 0108 return (m_symbols.contains(index) ? m_symbols.value(index) : Symbol()); 0109 } 0110 0111 /** 0112 * Take a symbol from the library. 0113 * Remove a symbol identified by it's index and return it. 0114 * The QListWidgetItem associated with the symbol is also removed and deleted. 0115 * If the index is not in the library it returns a default constructed symbol. 0116 * 0117 * @param index the index of the Symbol to be removed 0118 * 0119 * @return a Symbol 0120 */ 0121 Symbol SymbolLibrary::takeSymbol(qint16 index) 0122 { 0123 Symbol symbol; 0124 0125 if (m_symbols.contains(index)) { 0126 symbol = m_symbols.take(index); 0127 0128 if (m_listWidget) { 0129 m_listWidget->removeSymbol(index); 0130 } 0131 } 0132 0133 return symbol; 0134 } 0135 0136 /** 0137 * Update the Symbol for an index in the library. 0138 * If the index supplied is 0, a new index will be taken from the m_nextIndex value which is 0139 * then incremented. This value will be returned. 0140 * When a LibraryListWidget has been linked to the SymbolLibrary the symbol is added to the 0141 * LibraryListWidget. 0142 * 0143 * @param index a qint16 representing the index 0144 * @param symbol a const reference to a Symbol 0145 * 0146 * @return a qint16 representing the index, this is useful when the original index was 0 0147 */ 0148 qint16 SymbolLibrary::setSymbol(qint16 index, const Symbol &symbol) 0149 { 0150 if (!index) { 0151 index = m_nextIndex++; 0152 } 0153 0154 m_symbols.insert(index, symbol); 0155 0156 if (m_listWidget) { 0157 m_listWidget->addSymbol(index, symbol); 0158 } 0159 0160 return index; 0161 } 0162 0163 /** 0164 * Get the url for the file. 0165 * 0166 * @return a reference to a QUrl having the url of the file 0167 */ 0168 QUrl SymbolLibrary::url() const 0169 { 0170 return m_url; 0171 } 0172 0173 /** 0174 * Set the url for the file. 0175 * 0176 * @param url a const reference to a QUrl having the url of the file. 0177 */ 0178 void SymbolLibrary::setUrl(const QUrl &url) 0179 { 0180 m_url = url; 0181 m_name = url.fileName(); 0182 } 0183 0184 /** 0185 * Get the name of the symbol library. 0186 */ 0187 QString SymbolLibrary::name() const 0188 { 0189 return m_name; 0190 } 0191 0192 /** 0193 * Set the name of the symbol library. 0194 * 0195 * @param name the name to be set 0196 */ 0197 void SymbolLibrary::setName(const QString &name) 0198 { 0199 m_name = name; 0200 } 0201 0202 /** 0203 * Get a sorted list of symbol indexes 0204 * 0205 * @return a QList<qint16> of sorted indexes 0206 */ 0207 QList<qint16> SymbolLibrary::indexes() const 0208 { 0209 QList<qint16> keys = m_symbols.keys(); 0210 std::sort(keys.begin(), keys.end()); 0211 return keys; 0212 } 0213 0214 /** 0215 * Get a pointer to the symbol library undo stack. 0216 * 0217 * @return a pointer to a QUndoStack 0218 */ 0219 QUndoStack *SymbolLibrary::undoStack() 0220 { 0221 return &m_undoStack; 0222 } 0223 0224 /** 0225 * Generate all the items in the library. 0226 * This will be called when a library file is loaded to generate all the new 0227 * QListWidgetItems for the symbols in the library and generate an icon for it. 0228 * A list of sorted QMap keys is retrieved to allow adding items in the correct 0229 * order. 0230 */ 0231 void SymbolLibrary::generateItems() 0232 { 0233 if (!m_listWidget) { 0234 return; 0235 } 0236 0237 foreach (qint16 index, indexes()) { 0238 m_listWidget->addSymbol(index, m_symbols[index]); 0239 } 0240 } 0241 0242 /** 0243 * Stream out the file. 0244 * Symbol files are indicated with a magic string of KXStitchSymbols. The stream version is set 0245 * to maintain consistency with the streamed objects. 0246 * Write the version, current index and the map of symbols. 0247 * 0248 * @param stream a reference to a QDataStream 0249 * @param library a const reference to a SymbolLibrary 0250 * 0251 * @return a reference to a QDataStream 0252 */ 0253 QDataStream &operator<<(QDataStream &stream, const SymbolLibrary &library) 0254 { 0255 stream.writeRawData("KXStitchSymbols", 15); 0256 stream.setVersion(QDataStream::Qt_4_0); 0257 stream << library.version; 0258 stream << library.m_nextIndex; 0259 0260 if (stream.status() != QDataStream::Ok) { 0261 throw FailedWriteFile(stream.status()); 0262 } 0263 0264 stream << library.m_symbols; 0265 return stream; 0266 } 0267 0268 /** 0269 * Stream in the file. 0270 * Initially clear the current contents and reset the url. 0271 * Symbol files are indicated with a magic string of KXStitchSymbols. The stream version is set 0272 * to maintain consistency with the streamed objects. Read and check the magic string. If this 0273 * is not a symbol file throw an exception. 0274 * Read in the version. 0275 * Read the data for the specified version. The stream is checked for errors and an exception is 0276 * thrown if there was an error. 0277 * 0278 * @param stream a reference to a QDataStream 0279 * @param library a reference to a SymbolLibrary 0280 * 0281 * @return a reference to a QDataStream 0282 */ 0283 QDataStream &operator>>(QDataStream &stream, SymbolLibrary &library) 0284 { 0285 library.clear(); 0286 0287 char magic[15]; 0288 stream.readRawData(magic, 15); 0289 0290 if (strncmp(magic, "KXStitchSymbols", 15) == 0) { 0291 stream.setVersion(QDataStream::Qt_4_0); 0292 qint32 version; 0293 QMap<qint16, QPainterPath> paths_v100; 0294 QList<qint16> paths_v100_keys; 0295 stream >> version; 0296 0297 switch (version) { 0298 case 101: 0299 stream >> library.m_nextIndex; 0300 0301 if (stream.status() != QDataStream::Ok) { 0302 throw FailedReadFile(QString(i18n("Stream error"))); 0303 } 0304 0305 stream >> library.m_symbols; 0306 library.generateItems(); 0307 break; 0308 0309 case 100: 0310 stream >> library.m_nextIndex; 0311 library.m_nextIndex++; 0312 stream >> paths_v100; 0313 paths_v100_keys = paths_v100.keys(); 0314 0315 foreach (qint16 index, paths_v100_keys) { 0316 Symbol symbol; 0317 symbol.setPath(paths_v100[index]); 0318 library.setSymbol(index, symbol); 0319 } 0320 0321 break; 0322 0323 default: 0324 throw InvalidFileVersion(QString(i18n("Symbol file version %1", version))); 0325 break; 0326 } 0327 } else { 0328 throw InvalidFile(); 0329 } 0330 0331 return stream; 0332 }