Warning, file /graphics/glaxnimate/src/core/model/document.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 * SPDX-FileCopyrightText: 2019-2023 Mattia Basaglia <dev@dragon.best> 0003 * 0004 * SPDX-License-Identifier: GPL-3.0-or-later 0005 */ 0006 0007 #include "document.hpp" 0008 0009 #include <QRegularExpression> 0010 0011 #include "io/glaxnimate/glaxnimate_format.hpp" 0012 #include "model/assets/assets.hpp" 0013 #include "model/assets/pending_asset.hpp" 0014 0015 0016 class glaxnimate::model::Document::Private 0017 { 0018 public: 0019 using NameIndex = unsigned long long; 0020 0021 Private(Document* doc) 0022 : assets(doc) 0023 { 0024 io_options.format = io::glaxnimate::GlaxnimateFormat::instance(); 0025 } 0026 0027 std::pair<QString, NameIndex> name_index(const QString& name) const 0028 { 0029 static QRegularExpression detect_numbers("^(.*) ([0-9]+)$"); 0030 QRegularExpressionMatch match = detect_numbers.match(name); 0031 if ( match.hasMatch() ) 0032 { 0033 return {match.captured(1), match.captured(2).toULongLong()}; 0034 } 0035 0036 return {name, 0}; 0037 } 0038 0039 void increase(std::pair<QString, NameIndex> pair) 0040 { 0041 auto iter = name_indices.find(pair.first); 0042 0043 if ( iter != name_indices.end() ) 0044 { 0045 if ( iter->second < pair.second ) 0046 iter->second = pair.second; 0047 } 0048 else 0049 { 0050 name_indices.emplace(std::move(pair)); 0051 } 0052 } 0053 0054 void decrease(const std::pair<QString, NameIndex>& pair) 0055 { 0056 if ( pair.second == 0 ) 0057 return; 0058 0059 auto iter = name_indices.find(pair.first); 0060 0061 if ( iter != name_indices.end() ) 0062 { 0063 if ( iter->second == pair.second ) 0064 iter->second -= 1; 0065 } 0066 } 0067 0068 QString name_suggestion(const QString& base_name) 0069 { 0070 auto index_pair = name_index(base_name); 0071 auto iter = name_indices.find(index_pair.first); 0072 if ( iter == name_indices.end() ) 0073 return base_name; 0074 0075 return QString("%1 %2").arg(iter->first).arg(iter->second + 1); 0076 } 0077 0078 int add_pending_asset(QUrl url, QByteArray data, const QString& name_alias) 0079 { 0080 int id = max_pending_id; 0081 ++max_pending_id; 0082 pending_assets[id] = {id, std::move(url), std::move(data), name_alias}; 0083 return id; 0084 } 0085 0086 QUndoStack undo_stack; 0087 QVariantMap metadata; 0088 io::Options io_options; 0089 FrameTime current_time = 0; 0090 bool record_to_keyframe = false; 0091 Assets assets; 0092 glaxnimate::model::CompGraph comp_graph; 0093 std::unordered_map<QString, NameIndex> name_indices; 0094 std::map<int, PendingAsset> pending_assets; 0095 int max_pending_id = 0; 0096 DocumentInfo info; 0097 QUuid uuid; 0098 }; 0099 0100 0101 glaxnimate::model::Document::Document(const QString& filename) 0102 : d ( std::make_unique<glaxnimate::model::Document::Private>(this) ) 0103 { 0104 d->io_options.filename = filename; 0105 d->uuid = QUuid::createUuid(); 0106 } 0107 0108 glaxnimate::model::Document::~Document() = default; 0109 0110 QString glaxnimate::model::Document::filename() const 0111 { 0112 return d->io_options.filename; 0113 } 0114 0115 QUuid glaxnimate::model::Document::uuid() const 0116 { 0117 return d->uuid; 0118 } 0119 0120 QVariantMap & glaxnimate::model::Document::metadata() 0121 { 0122 return d->metadata; 0123 } 0124 0125 QUndoStack & glaxnimate::model::Document::undo_stack() 0126 { 0127 return d->undo_stack; 0128 } 0129 0130 const glaxnimate::io::Options & glaxnimate::model::Document::io_options() const 0131 { 0132 return d->io_options; 0133 } 0134 0135 void glaxnimate::model::Document::set_io_options(const io::Options& opt) 0136 { 0137 bool em = opt.filename != d->io_options.filename; 0138 d->io_options = opt; 0139 if ( em ) 0140 Q_EMIT filename_changed(d->io_options.filename); 0141 } 0142 0143 glaxnimate::model::DocumentNode * glaxnimate::model::Document::find_by_uuid(const QUuid& n) const 0144 { 0145 return d->assets.docnode_find_by_uuid(n); 0146 } 0147 0148 glaxnimate::model::DocumentNode * glaxnimate::model::Document::find_by_name(const QString& name) const 0149 { 0150 return d->assets.docnode_find_by_name(name); 0151 } 0152 0153 QVariantList glaxnimate::model::Document::find_by_type_name(const QString& type_name) const 0154 { 0155 return d->assets.find_by_type_name(type_name); 0156 } 0157 0158 bool glaxnimate::model::Document::redo() 0159 { 0160 if ( ! d->undo_stack.canRedo() ) 0161 return false; 0162 d->undo_stack.redo(); 0163 return true; 0164 } 0165 0166 bool glaxnimate::model::Document::undo() 0167 { 0168 if ( ! d->undo_stack.canUndo() ) 0169 return false; 0170 d->undo_stack.undo(); 0171 return true; 0172 } 0173 0174 glaxnimate::model::FrameTime glaxnimate::model::Document::current_time() const 0175 { 0176 return d->current_time; 0177 } 0178 0179 void glaxnimate::model::Document::set_current_time(glaxnimate::model::FrameTime t) 0180 { 0181 d->assets.set_time(t); 0182 Q_EMIT current_time_changed(d->current_time = t); 0183 } 0184 0185 0186 bool glaxnimate::model::Document::record_to_keyframe() const 0187 { 0188 return d->record_to_keyframe; 0189 } 0190 0191 void glaxnimate::model::Document::set_record_to_keyframe(bool r) 0192 { 0193 Q_EMIT record_to_keyframe_changed(d->record_to_keyframe = r); 0194 } 0195 0196 void glaxnimate::model::Document::push_command(QUndoCommand* cmd) 0197 { 0198 d->undo_stack.push(cmd); 0199 } 0200 0201 QString glaxnimate::model::Document::get_best_name(glaxnimate::model::DocumentNode* node, const QString& suggestion) const 0202 { 0203 if ( !node ) 0204 return {}; 0205 0206 if ( suggestion.isEmpty() ) 0207 return d->name_suggestion(node->type_name_human()); 0208 0209 return d->name_suggestion(suggestion); 0210 0211 } 0212 0213 void glaxnimate::model::Document::set_best_name(glaxnimate::model::DocumentNode* node, const QString& suggestion) const 0214 { 0215 if ( node ) 0216 node->name.set(get_best_name(node, suggestion)); 0217 } 0218 0219 glaxnimate::model::Assets * glaxnimate::model::Document::assets() const 0220 { 0221 return &d->assets; 0222 } 0223 0224 glaxnimate::model::Object * glaxnimate::model::Document::assets_obj() const 0225 { 0226 return assets(); 0227 } 0228 0229 void glaxnimate::model::Document::set_metadata(const QVariantMap& meta) 0230 { 0231 d->metadata = meta; 0232 } 0233 0234 glaxnimate::model::CompGraph & glaxnimate::model::Document::comp_graph() 0235 { 0236 return d->comp_graph; 0237 } 0238 0239 void glaxnimate::model::Document::decrease_node_name(const QString& old_name) 0240 { 0241 if ( !old_name.isEmpty() ) 0242 d->decrease(d->name_index(old_name)); 0243 } 0244 0245 void glaxnimate::model::Document::increase_node_name(const QString& new_name) 0246 { 0247 if ( !new_name.isEmpty() ) 0248 d->increase(d->name_index(new_name)); 0249 } 0250 0251 0252 void glaxnimate::model::Document::stretch_time(qreal multiplier) 0253 { 0254 qreal time = d->current_time; 0255 d->assets.stretch_time(multiplier); 0256 set_current_time(qRound(time * multiplier)); 0257 } 0258 0259 int glaxnimate::model::Document::add_pending_asset(const QString& name, const QByteArray& data) 0260 { 0261 return d->add_pending_asset({}, data, name); 0262 } 0263 0264 int glaxnimate::model::Document::add_pending_asset(const QString& name, const QUrl& url) 0265 { 0266 return d->add_pending_asset(url, {}, name); 0267 } 0268 0269 int glaxnimate::model::Document::add_pending_asset(const PendingAsset& ass) 0270 { 0271 return d->add_pending_asset(ass.url, ass.data, ass.name_alias); 0272 } 0273 0274 void glaxnimate::model::Document::mark_asset_loaded(int id) 0275 { 0276 auto it = d->pending_assets.find(id); 0277 if ( it != d->pending_assets.end() ) 0278 it->second.loaded = true; 0279 } 0280 0281 std::vector<glaxnimate::model::PendingAsset> glaxnimate::model::Document::pending_assets() 0282 { 0283 std::vector<PendingAsset> assets; 0284 assets.reserve(d->pending_assets.size()); 0285 for ( const auto& ass : d->pending_assets ) 0286 assets.push_back(ass.second); 0287 0288 return assets; 0289 } 0290 0291 void glaxnimate::model::Document::clear_pending_assets() 0292 { 0293 for ( auto& ass : d->pending_assets ) 0294 ass.second.loaded = true; 0295 } 0296 0297 0298 glaxnimate::model::Document::DocumentInfo & glaxnimate::model::Document::info() 0299 { 0300 return d->info; 0301 }