# HG changeset patch # User Teemu Piippo # Date 1442954299 -10800 # Node ID 1b49f34e533d75b0e173ae14b77d4f02edfae9fe # Parent 7986584e74988b389bf42837649102a2e08fd36f Commit work done on document manager. Happy 3rd birthday LDForge! diff -r 7986584e7498 -r 1b49f34e533d CMakeLists.txt --- a/CMakeLists.txt Sun Sep 06 20:45:51 2015 +0300 +++ b/CMakeLists.txt Tue Sep 22 23:38:19 2015 +0300 @@ -39,6 +39,7 @@ src/dialogs.cpp src/documentation.cpp src/documentloader.cpp + src/documentmanager.cpp src/editHistory.cpp src/glRenderer.cpp src/glCompiler.cpp @@ -87,6 +88,7 @@ src/dialogs.h src/documentation.h src/documentloader.h + src/documentmanager.h src/doublemap.h src/editHistory.h src/format.h diff -r 7986584e7498 -r 1b49f34e533d src/dialogs/configdialog.cpp --- a/src/dialogs/configdialog.cpp Sun Sep 06 20:45:51 2015 +0300 +++ b/src/dialogs/configdialog.cpp Tue Sep 22 23:38:19 2015 +0300 @@ -550,7 +550,7 @@ for (ShortcutListItem* item : sel) { - item->setSequence (MainWindow::defaultShortcut (item->action())); + item->setSequence (m_window->defaultShortcut (item->action())); setShortcutText (item); } } diff -r 7986584e7498 -r 1b49f34e533d src/documentmanager.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/documentmanager.cpp Tue Sep 22 23:38:19 2015 +0300 @@ -0,0 +1,431 @@ +/* + * LDForge: LDraw parts authoring CAD + * Copyright (C) 2013 - 2015 Teemu Piippo + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include "documentmanager.h" +#include "ldDocument.h" +#include "mainwindow.h" +#include "partdownloader.h" + +enum +{ + MAX_RECENT_FILES = 10 +}; + +DocumentManager::DocumentManager (QObject* parent) : + QObject (parent), + g_loadingMainFile (false), + g_loadingLogoedStuds (false), + g_logoedStud (nullptr), + g_logoedStud2 (nullptr) {} + +DocumentManager::~DocumentManager() +{ + clear(); +} + +void DocumentManager::clear() +{ + for (DocumentMapIterator it (m_documents); it.hasNext();) + { + LDDocument* document = it.next().value(); + document->close(); + delete document; + } + + m_documents.clear(); +} + +LDDocument* DocumentManager::getDocumentByName (QString filename) +{ + // Try find the file in the list of loaded files + LDDocument* doc = findDocumentByName (filename); + + // If it's not loaded, try open it + if (not doc) + doc = openDocument (filename, true, true); + + return doc; +} + +void DocumentManager::openMainModel (QString path) +{ + // If there's already a file with the same name, this file must replace it. + LDDocument* documentToReplace = nullptr; + LDDocument* file = nullptr; + QString shortName = LDDocument::shortenName (path); + + for (LDDocument* doc : m_window->allDocuments()) + { + if (doc->name() == shortName) + { + documentToReplace = doc; + break; + } + } + + // We cannot open this file if the document this would replace is not + // safe to close. + if (documentToReplace and not documentToReplace->isSafeToClose()) + return; + + g_loadingMainFile = true; + + // If we're replacing an existing document, clear the document and + // make it ready for being loaded to. + if (documentToReplace) + { + file = documentToReplace; + file->clear(); + } + + bool aborted; + file = openDocument (path, false, false, file, &aborted); + + if (file == nullptr) + { + if (not aborted) + { + // Tell the user loading failed. + setlocale (LC_ALL, "C"); + Critical (format (tr ("Failed to open %1: %2"), path, strerror (errno))); + } + + g_loadingMainFile = false; + return; + } + + file->openForEditing(); + m_window->closeInitialDocument(); + m_window->changeDocument (file); + m_window->doFullRefresh(); + addRecentFile (path); + g_loadingMainFile = false; + + // If there were problems loading subfile references, try see if we can find these + // files on the parts tracker. + QStringList unknowns; + + for (LDObject* obj : file->objects()) + { + if (obj->type() != OBJ_Error or static_cast (obj)->fileReferenced().isEmpty()) + continue; + + unknowns << static_cast (obj)->fileReferenced(); + } + + if (m_window->configBag()->tryDownloadMissingFiles() and not unknowns.isEmpty()) + { + PartDownloader dl (m_window); + dl.setSourceType (PartDownloader::PartsTracker); + dl.setPrimaryFile (file); + + for (QString const& unknown : unknowns) + dl.downloadFromPartsTracker (unknown); + + dl.exec(); + dl.checkIfFinished(); + file->reloadAllSubfiles(); + } +} + +LDDocument* DocumentManager::findDocumentByName (QString name) +{ + for (DocumentMapIterator it (m_documents); it.hasNext();) + { + LDDocument* document = it.next().value(); + + if (isOneOf (name, document->name(), document->defaultName())) + return document; + } + + return nullptr; +} + +QString Dirname (QString path) +{ + int lastpos = path.lastIndexOf (DIRSLASH); + + if (lastpos > 0) + return path.left (lastpos); + +#ifndef _WIN32 + if (path[0] == DIRSLASH_CHAR) + return DIRSLASH; +#endif // _WIN32 + + return ""; +} + +QString Basename (QString path) +{ + int lastpos = path.lastIndexOf (DIRSLASH); + + if (lastpos != -1) + return path.mid (lastpos + 1); + + return path; +} + +QString DocumentManager::findDocumentPath (QString relativePath, bool subdirs) +{ + QString fullPath; + + // LDraw models use backslashes as path separators. Replace those into forward slashes for Qt. + relativePath.replace ("\\", "/"); + + // Try find it relative to other currently open documents. We want a file in the immediate vicinity of a current + // part model to override stock LDraw stuff. + QString reltop = Basename (Dirname (relativePath)); + + for (LDDocument* doc : m_window->allDocuments()) + { + QString partpath = format ("%1/%2", Dirname (doc->fullPath()), relativePath); + QFile f (partpath); + + if (f.exists()) + { + // ensure we don't mix subfiles and 48-primitives with non-subfiles and non-48 + QString proptop = Basename (Dirname (partpath)); + + bool bogus = false; + + for (QString s : g_specialSubdirectories) + { + if ((proptop == s and reltop != s) or (reltop == s and proptop != s)) + { + bogus = true; + break; + } + } + + if (not bogus) + return partpath; + } + } + + if (QFile::exists (relativePath)) + return relativePath; + + // Try with just the LDraw path first + fullPath = format ("%1" DIRSLASH "%2", m_window->configBag()->lDrawPath(), relativePath); + + if (QFile::exists (fullPath)) + return fullPath; + + if (subdirs) + { + // Look in sub-directories: parts and p. Also look in the download path, since that's where we download parts + // from the PT to. + QStringList dirs = { m_window->configBag()->lDrawPath(), m_window->configBag()->downloadFilePath() }; + for (const QString& topdir : dirs) + { + for (const QString& subdir : QStringList ({ "parts", "p" })) + { + fullPath = format ("%1" DIRSLASH "%2" DIRSLASH "%3", topdir, subdir, relativePath); + + if (QFile::exists (fullPath)) + return fullPath; + } + } + } + + // Did not find the file. + return ""; +} + +QFile* DocumentManager::openLDrawFile (QString relpath, bool subdirs, QString* pathpointer) +{ + print ("Opening %1...\n", relpath); + QString path = findDocumentPath (relpath, subdirs); + + if (pathpointer) + *pathpointer = path; + + if (path.isEmpty()) + return nullptr; + + QFile* fp = new QFile (path); + + if (fp->open (QIODevice::ReadOnly)) + return fp; + + fp->deleteLater(); + return nullptr; +} + +LDObjectList DocumentManager::loadFileContents (QFile* fp, int* numWarnings, bool* ok) +{ + LDObjectList objs; + + if (numWarnings) + *numWarnings = 0; + + DocumentLoader* loader = new DocumentLoader (g_loadingMainFile); + loader->read (fp); + loader->start(); + + // After start() returns, if the loader isn't done yet, it's delaying + // its next iteration through the event loop. We need to catch this here + // by telling the event loop to tick, which will tick the file loader again. + // We keep doing this until the file loader is ready. + while (not loader->isDone()) + qApp->processEvents(); + + // If we wanted the success value, supply that now + if (ok) + *ok = not loader->hasAborted(); + + objs = loader->objects(); + delete loader; + return objs; +} + +LDDocument* DocumentManager::openDocument (QString path, bool search, bool implicit, LDDocument* fileToOverride, bool* aborted) +{ + // Convert the file name to lowercase when searching because some parts contain subfile + // subfile references with uppercase file names. I'll assume here that the library will always + // use lowercase file names for the part files. + QFile* fp; + QString fullpath; + + if (search) + { + fp = openLDrawFile (path.toLower(), true, &fullpath); + } + else + { + fp = new QFile (path); + fullpath = path; + + if (not fp->open (QIODevice::ReadOnly)) + { + delete fp; + return nullptr; + } + } + + if (not fp) + return nullptr; + + LDDocument* load = (fileToOverride ? fileToOverride : m_window->newDocument (implicit)); + load->setFullPath (fullpath); + load->setName (LDDocument::shortenName (load->fullPath())); + + // Loading the file shouldn't count as actual edits to the document. + load->history()->setIgnoring (true); + + int numWarnings; + bool ok; + LDObjectList objs = loadFileContents (fp, &numWarnings, &ok); + fp->close(); + fp->deleteLater(); + + if (aborted) + *aborted = ok == false; + + if (not ok) + { + load->close(); + return nullptr; + } + + load->addObjects (objs); + + if (g_loadingMainFile) + { + m_window->changeDocument (load); + m_window->renderer()->setDocument (load); + print (tr ("File %1 parsed successfully (%2 errors)."), path, numWarnings); + } + + load->history()->setIgnoring (false); + return load; +} + +void DocumentManager::closeAllDocuments() +{ + for (LDDocument* file : m_window->allDocuments()) + file->close(); +} + +void DocumentManager::addRecentFile (QString path) +{ + QStringList recentFiles = m_window->configBag()->recentFiles(); + int idx = recentFiles.indexOf (path); + + // If this file already is in the list, pop it out. + if (idx != -1) + { + if (idx == recentFiles.size() - 1) + return; // first recent file - abort and do nothing + + recentFiles.removeAt (idx); + } + + // If there's too many recent files, drop one out. + while (recentFiles.size() > (MAX_RECENT_FILES - 1)) + recentFiles.removeAt (0); + + // Add the file + recentFiles << path; + m_window->configBag()->setRecentFiles (recentFiles); + m_window->syncSettings(); + m_window->updateRecentFilesMenu(); +} + +bool DocumentManager::isSafeToCloseAll() +{ + for (LDDocument* f : m_window->allDocuments()) + { + if (not f->isSafeToClose()) + return false; + } + + return true; +} + +void DocumentManager::loadLogoedStuds() +{ + if (g_loadingLogoedStuds or (g_logoedStud and g_logoedStud2)) + return; + + g_loadingLogoedStuds = true; + g_logoedStud = openDocument ("stud-logo.dat", true, true); + g_logoedStud2 = openDocument ("stud2-logo.dat", true, true); + print (tr ("Logoed studs loaded.\n")); + g_loadingLogoedStuds = false; +} + +bool DocumentManager::preInline (LDDocument* doc, LDObjectList& objs) +{ + // Possibly substitute with logoed studs: + // stud.dat -> stud-logo.dat + // stud2.dat -> stud-logo2.dat + if (m_config->useLogoStuds() and renderinline) + { + // Ensure logoed studs are loaded first + loadLogoedStuds(); + + if (doc->name() == "stud.dat" and g_logoedStud) + return g_logoedStud->inlineContents (deep, renderinline); + else if (doc->name() == "stud2.dat" and g_logoedStud2) + return g_logoedStud2->inlineContents (deep, renderinline); + } +} diff -r 7986584e7498 -r 1b49f34e533d src/documentmanager.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/documentmanager.h Tue Sep 22 23:38:19 2015 +0300 @@ -0,0 +1,57 @@ +/* + * LDForge: LDraw parts authoring CAD + * Copyright (C) 2013 - 2015 Teemu Piippo + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include "main.h" +#include "hierarchyelement.h" + +class DocumentManager : public QObject, public HierarchyElement +{ + Q_OBJECT + +public: + using DocumentMap = QHash; + using DocumentMapIterator = QHashIterator; + + DocumentManager (QObject* parent = nullptr); + ~DocumentManager(); + + void addRecentFile (QString path); + void clear(); + void closeAllDocuments(); + LDDocument* findDocumentByName (QString name); + QString findDocumentPath (QString relpath, bool subdirs); + LDDocument* getDocumentByName (QString filename); + bool isSafeToCloseAll(); + void loadLogoedStuds(); + LDDocument* openDocument (QString path, bool search, bool implicit, LDDocument* fileToOverride, bool* aborted); + QFile* openLDrawFile (QString relpath, bool subdirs, QString* pathpointer); + void openMainModel (QString path); + bool preInline (LDDocument* doc, LDObjectList& objs); + +private: + DocumentMap m_documents; + bool g_loadingMainFile; + bool g_loadingLogoedStuds; + LDDocument* g_logoedStud; + LDDocument* g_logoedStud2; + + LDObjectList loadFileContents (QFile* fp, int* numWarnings, bool* ok); +}; + +static const QStringList g_specialSubdirectories ({ "s", "48", "8" }); \ No newline at end of file diff -r 7986584e7498 -r 1b49f34e533d src/hierarchyelement.cpp --- a/src/hierarchyelement.cpp Sun Sep 06 20:45:51 2015 +0300 +++ b/src/hierarchyelement.cpp Tue Sep 22 23:38:19 2015 +0300 @@ -24,6 +24,7 @@ } m_config = m_window->configBag(); + m_documents = m_window->documents(); } GuiUtilities* HierarchyElement::guiUtilities() const diff -r 7986584e7498 -r 1b49f34e533d src/hierarchyelement.h --- a/src/hierarchyelement.h Sun Sep 06 20:45:51 2015 +0300 +++ b/src/hierarchyelement.h Tue Sep 22 23:38:19 2015 +0300 @@ -6,6 +6,7 @@ class ConfigurationValueBag; class GuiUtilities; class LDDocument; +class DocumentManager; // // Objects that are to take part in the MainWindow's hierarchy multiple-inherit from this class to get a few useful @@ -23,4 +24,5 @@ protected: MainWindow* m_window; ConfigurationValueBag* m_config; + DocumentManager* m_documents; }; diff -r 7986584e7498 -r 1b49f34e533d src/ldDocument.cpp --- a/src/ldDocument.cpp Sun Sep 06 20:45:51 2015 +0300 +++ b/src/ldDocument.cpp Tue Sep 22 23:38:19 2015 +0300 @@ -36,14 +36,7 @@ ConfigOption (QStringList RecentFiles) ConfigOption (bool TryDownloadMissingFiles = false) -static bool g_loadingMainFile = false; -enum { MAX_RECENT_FILES = 10 }; -static LDDocument* g_logoedStud; -static LDDocument* g_logoedStud2; -static bool g_loadingLogoedStuds = false; -const QStringList g_specialSubdirectories ({ "s", "48", "8" }); - -LDDocument::LDDocument (QObject* parent) : +LDDocument::LDDocument (DocumentManager* parent) : QObject (parent), HierarchyElement (parent), m_history (new EditHistory (this)), @@ -51,7 +44,8 @@ m_verticesOutdated (true), m_needVertexMerge (true), m_beingDestroyed (false), - m_gldata (new LDGLData) + m_gldata (new LDGLData), + m_manager (parent) { setSavePosition (-1); setTabIndex (-1); @@ -60,6 +54,9 @@ LDDocument::~LDDocument() { + for (int i = 0; i < m_objects.size(); ++i) + delete m_objects[i]; + m_beingDestroyed = true; delete m_history; delete m_gldata; @@ -195,232 +192,6 @@ // ============================================================================= // -LDDocument* FindDocument (QString name) -{ - for (LDDocument* document : g_win->allDocuments()) - { - if (isOneOf (name, document->name(), document->defaultName())) - return document; - } - - return nullptr; -} - -// ============================================================================= -// -QString Dirname (QString path) -{ - long lastpos = path.lastIndexOf (DIRSLASH); - - if (lastpos > 0) - return path.left (lastpos); - -#ifndef _WIN32 - if (path[0] == DIRSLASH_CHAR) - return DIRSLASH; -#endif // _WIN32 - - return ""; -} - -// ============================================================================= -// -QString Basename (QString path) -{ - long lastpos = path.lastIndexOf (DIRSLASH); - - if (lastpos != -1) - return path.mid (lastpos + 1); - - return path; -} - -// ============================================================================= -// -static QString FindDocumentPath (QString relpath, bool subdirs) -{ - QString fullPath; - - // LDraw models use backslashes as path separators. Replace those into forward slashes for Qt. - relpath.replace ("\\", "/"); - - // Try find it relative to other currently open documents. We want a file in the immediate vicinity of a current - // part model to override stock LDraw stuff. - QString reltop = Basename (Dirname (relpath)); - - for (LDDocument* doc : g_win->allDocuments()) - { - QString partpath = format ("%1/%2", Dirname (doc->fullPath()), relpath); - QFile f (partpath); - - if (f.exists()) - { - // ensure we don't mix subfiles and 48-primitives with non-subfiles and non-48 - QString proptop = Basename (Dirname (partpath)); - - bool bogus = false; - - for (QString s : g_specialSubdirectories) - { - if ((proptop == s and reltop != s) or (reltop == s and proptop != s)) - { - bogus = true; - break; - } - } - - if (not bogus) - return partpath; - } - } - - if (QFile::exists (relpath)) - return relpath; - - // Try with just the LDraw path first - fullPath = format ("%1" DIRSLASH "%2", g_win->configBag()->lDrawPath(), relpath); - - if (QFile::exists (fullPath)) - return fullPath; - - if (subdirs) - { - // Look in sub-directories: parts and p. Also look in the download path, since that's where we download parts - // from the PT to. - QStringList dirs = { g_win->configBag()->lDrawPath(), g_win->configBag()->downloadFilePath() }; - for (const QString& topdir : dirs) - { - for (const QString& subdir : QStringList ({ "parts", "p" })) - { - fullPath = format ("%1" DIRSLASH "%2" DIRSLASH "%3", topdir, subdir, relpath); - - if (QFile::exists (fullPath)) - return fullPath; - } - } - } - - // Did not find the file. - return ""; -} - -// ============================================================================= -// -QFile* OpenLDrawFile (QString relpath, bool subdirs, QString* pathpointer) -{ - print ("Opening %1...\n", relpath); - QString path = FindDocumentPath (relpath, subdirs); - - if (pathpointer) - *pathpointer = path; - - if (path.isEmpty()) - return nullptr; - - QFile* fp = new QFile (path); - - if (fp->open (QIODevice::ReadOnly)) - return fp; - - fp->deleteLater(); - return nullptr; -} - -// ============================================================================= -// -LDObjectList LoadFileContents (QFile* fp, int* numWarnings, bool* ok) -{ - LDObjectList objs; - - if (numWarnings) - *numWarnings = 0; - - DocumentLoader* loader = new DocumentLoader (g_loadingMainFile); - loader->read (fp); - loader->start(); - - // After start() returns, if the loader isn't done yet, it's delaying - // its next iteration through the event loop. We need to catch this here - // by telling the event loop to tick, which will tick the file loader again. - // We keep doing this until the file loader is ready. - while (not loader->isDone()) - qApp->processEvents(); - - // If we wanted the success value, supply that now - if (ok) - *ok = not loader->hasAborted(); - - objs = loader->objects(); - delete loader; - return objs; -} - -// ============================================================================= -// -LDDocument* OpenDocument (QString path, bool search, bool implicit, LDDocument* fileToOverride, bool* aborted) -{ - // Convert the file name to lowercase when searching because some parts contain subfile - // subfile references with uppercase file names. I'll assume here that the library will always - // use lowercase file names for the part files. - QFile* fp; - QString fullpath; - - if (search) - { - fp = OpenLDrawFile (path.toLower(), true, &fullpath); - } - else - { - fp = new QFile (path); - fullpath = path; - - if (not fp->open (QIODevice::ReadOnly)) - { - delete fp; - return nullptr; - } - } - - if (not fp) - return nullptr; - - LDDocument* load = (fileToOverride ? fileToOverride : g_win->newDocument (implicit)); - load->setFullPath (fullpath); - load->setName (LDDocument::shortenName (load->fullPath())); - - // Loading the file shouldn't count as actual edits to the document. - load->history()->setIgnoring (true); - - int numWarnings; - bool ok; - LDObjectList objs = LoadFileContents (fp, &numWarnings, &ok); - fp->close(); - fp->deleteLater(); - - if (aborted) - *aborted = ok == false; - - if (not ok) - { - load->close(); - return nullptr; - } - - load->addObjects (objs); - - if (g_loadingMainFile) - { - g_win->changeDocument (load); - g_win->renderer()->setDocument (load); - print (QObject::tr ("File %1 parsed successfully (%2 errors)."), path, numWarnings); - } - - load->history()->setIgnoring (false); - return load; -} - -// ============================================================================= -// // Performs safety checks. Do this before closing any files! // bool LDDocument::isSafeToClose() @@ -479,125 +250,6 @@ // ============================================================================= // -void CloseAllDocuments() -{ - for (LDDocument* file : g_win->allDocuments()) - file->close(); -} - -// ============================================================================= -// -void AddRecentFile (QString path) -{ - QStringList recentFiles = g_win->configBag()->recentFiles(); - int idx = recentFiles.indexOf (path); - - // If this file already is in the list, pop it out. - if (idx != -1) - { - if (idx == recentFiles.size() - 1) - return; // first recent file - abort and do nothing - - recentFiles.removeAt (idx); - } - - // If there's too many recent files, drop one out. - while (recentFiles.size() > (MAX_RECENT_FILES - 1)) - recentFiles.removeAt (0); - - // Add the file - recentFiles << path; - g_win->configBag()->setRecentFiles (recentFiles); - g_win->syncSettings(); - g_win->updateRecentFilesMenu(); -} - -// ============================================================================= -// Open an LDraw file and set it as the main model -// ============================================================================= -void OpenMainModel (QString path) -{ - // If there's already a file with the same name, this file must replace it. - LDDocument* documentToReplace = nullptr; - LDDocument* file = nullptr; - QString shortName = LDDocument::shortenName (path); - - for (LDDocument* doc : g_win->allDocuments()) - { - if (doc->name() == shortName) - { - documentToReplace = doc; - break; - } - } - - // We cannot open this file if the document this would replace is not - // safe to close. - if (documentToReplace and not documentToReplace->isSafeToClose()) - return; - - g_loadingMainFile = true; - - // If we're replacing an existing document, clear the document and - // make it ready for being loaded to. - if (documentToReplace) - { - file = documentToReplace; - file->clear(); - } - - bool aborted; - file = OpenDocument (path, false, false, file, &aborted); - - if (file == nullptr) - { - if (not aborted) - { - // Tell the user loading failed. - setlocale (LC_ALL, "C"); - Critical (format (QObject::tr ("Failed to open %1: %2"), path, strerror (errno))); - } - - g_loadingMainFile = false; - return; - } - - file->openForEditing(); - g_win->closeInitialDocument(); - g_win->changeDocument (file); - g_win->doFullRefresh(); - AddRecentFile (path); - g_loadingMainFile = false; - - // If there were problems loading subfile references, try see if we can find these - // files on the parts tracker. - QStringList unknowns; - - for (LDObject* obj : file->objects()) - { - if (obj->type() != OBJ_Error or static_cast (obj)->fileReferenced().isEmpty()) - continue; - - unknowns << static_cast (obj)->fileReferenced(); - } - - if (g_win->configBag()->tryDownloadMissingFiles() and not unknowns.isEmpty()) - { - PartDownloader dl (g_win); - dl.setSourceType (PartDownloader::PartsTracker); - dl.setPrimaryFile (file); - - for (QString const& unknown : unknowns) - dl.downloadFromPartsTracker (unknown); - - dl.exec(); - dl.checkIfFinished(); - file->reloadAllSubfiles(); - } -} - -// ============================================================================= -// bool LDDocument::save (QString path, int64* sizeptr) { if (isCache()) @@ -900,20 +552,6 @@ // ============================================================================= // -LDDocument* GetDocument (QString filename) -{ - // Try find the file in the list of loaded files - LDDocument* doc = FindDocument (filename); - - // If it's not loaded, try open it - if (not doc) - doc = OpenDocument (filename, true, true); - - return doc; -} - -// ============================================================================= -// void LDDocument::reloadAllSubfiles() { print ("Reloading subfiles of %1", getDisplayName()); @@ -1026,19 +664,6 @@ // ============================================================================= // -bool IsSafeToCloseAll() -{ - for (LDDocument* f : g_win->allDocuments()) - { - if (not f->isSafeToClose()) - return false; - } - - return true; -} - -// ============================================================================= -// void LDDocument::setObject (int idx, LDObject* obj) { if (idx < 0 or idx >= m_objects.size()) @@ -1169,21 +794,10 @@ // ----------------------------------------------------------------------------- LDObjectList LDDocument::inlineContents (bool deep, bool renderinline) { - // Possibly substitute with logoed studs: - // stud.dat -> stud-logo.dat - // stud2.dat -> stud-logo2.dat - if (m_config->useLogoStuds() and renderinline) - { - // Ensure logoed studs are loaded first - LoadLogoStuds(); + LDObjectList objs, objcache; - if (name() == "stud.dat" and g_logoedStud) - return g_logoedStud->inlineContents (deep, renderinline); - else if (name() == "stud2.dat" and g_logoedStud2) - return g_logoedStud2->inlineContents (deep, renderinline); - } - - LDObjectList objs, objcache; + if (m_manager->preInline (this, objs)) + return objs; // Manager dealt with this inline for (LDObject* obj : objects()) { @@ -1207,20 +821,6 @@ // ============================================================================= // -void LoadLogoStuds() -{ - if (g_loadingLogoedStuds or (g_logoedStud and g_logoedStud2)) - return; - - g_loadingLogoedStuds = true; - g_logoedStud = OpenDocument ("stud-logo.dat", true, true); - g_logoedStud2 = OpenDocument ("stud2-logo.dat", true, true); - print (QObject::tr ("Logoed studs loaded.\n")); - g_loadingLogoedStuds = false; -} - -// ============================================================================= -// void LDDocument::addToSelection (LDObject* obj) // [protected] { if (obj->isSelected() and obj->document() == this) diff -r 7986584e7498 -r 1b49f34e533d src/ldDocument.h --- a/src/ldDocument.h Sun Sep 06 20:45:51 2015 +0300 +++ b/src/ldDocument.h Tue Sep 22 23:38:19 2015 +0300 @@ -27,6 +27,7 @@ class OpenProgressDialog; struct LDGLData; class GLCompiler; +class DocumentManager; // // This class stores a document either as a editable file for the user or for @@ -43,7 +44,7 @@ Q_OBJECT public: - LDDocument (QObject* parent); + LDDocument (DocumentManager* parent); ~LDDocument(); void addHistoryStep(); @@ -117,31 +118,12 @@ QVector m_vertices; LDObjectList m_sel; LDGLData* m_gldata; + DocumentManager* m_manager; }; -// Opens the given file as the main file. Everything is closed first. -void OpenMainModel (QString path); - -// Finds an OpenFile by name or null if not open -LDDocument* FindDocument (QString name); - -// Opens the given file and parses the LDraw code within. Returns a pointer -// to the opened file or null on error. -LDDocument* OpenDocument (QString path, bool search, bool implicit, LDDocument* fileToOverride = nullptr, bool* aborted = nullptr); - -// Opens the given file and returns a pointer to it, potentially looking in /parts and /p -QFile* OpenLDrawFile (QString relpath, bool subdirs, QString* pathpointer = nullptr); - -// Close all open files, whether user-opened or subfile caches. -void CloseAllDocuments(); - // Parses a string line containing an LDraw object and returns the object parsed. LDObject* ParseLine (QString line); -// Retrieves the pointer to the given document by file name. Document is loaded -// from file if necessary. Can return null if neither succeeds. -LDDocument* GetDocument (QString filename); - // Is it safe to close all files? bool IsSafeToCloseAll(); diff -r 7986584e7498 -r 1b49f34e533d src/mainwindow.cpp --- a/src/mainwindow.cpp Sun Sep 06 20:45:51 2015 +0300 +++ b/src/mainwindow.cpp Tue Sep 22 23:38:19 2015 +0300 @@ -54,6 +54,7 @@ #include "dialogs/configdialog.h" #include "guiutilities.h" #include "glCompiler.h" +#include "documentmanager.h" static bool g_isSelectionLocked = false; static QMap g_defaultShortcuts; @@ -72,6 +73,7 @@ ui (*new Ui_MainWindow), m_externalPrograms (nullptr), m_settings (makeSettings (this)), + m_documents (new DocumentManager (this)), m_currentDocument (nullptr) { g_win = this; @@ -1132,7 +1134,7 @@ // --------------------------------------------------------------------------------------------------------------------- // -QKeySequence MainWindow::defaultShortcut (QAction* act) // [static] +QKeySequence MainWindow::defaultShortcut (QAction* act) { return g_defaultShortcuts[act]; } diff -r 7986584e7498 -r 1b49f34e533d src/mainwindow.h --- a/src/mainwindow.h Sun Sep 06 20:45:51 2015 +0300 +++ b/src/mainwindow.h Tue Sep 22 23:38:19 2015 +0300 @@ -79,9 +79,10 @@ void createBlankDocument(); LDDocument* currentDocument(); void currentDocumentClosed(); - static QKeySequence defaultShortcut (QAction* act); + QKeySequence defaultShortcut (QAction* act); void deleteByColor (LDColor color); int deleteSelection(); + DocumentManager* documents() { return m_documents; } void doFullRefresh(); void endAction(); class ExtProgramToolset* externalPrograms(); @@ -145,7 +146,7 @@ QMap m_toolmap; class ExtProgramToolset* m_externalPrograms; class QSettings* m_settings; - QList m_documents; + DocumentManager* m_documents; LDDocument* m_currentDocument; DoubleMap m_objectsInList;