37 QObject (parent), |
37 QObject (parent), |
38 HierarchyElement (parent), |
38 HierarchyElement (parent), |
39 m_loadingMainFile (false), |
39 m_loadingMainFile (false), |
40 m_isLoadingLogoedStuds (false), |
40 m_isLoadingLogoedStuds (false), |
41 m_logoedStud (nullptr), |
41 m_logoedStud (nullptr), |
42 m_logoedStud2 (nullptr) {} |
42 m_logoedStud2 (nullptr) |
|
43 { |
|
44 m_libraries.addLibrary(configuration().lDrawPath(), "LDraw library"); |
|
45 } |
43 |
46 |
44 DocumentManager::~DocumentManager() |
47 DocumentManager::~DocumentManager() |
45 { |
48 { |
46 clear(); |
49 clear(); |
47 } |
50 } |
187 return path.mid (lastpos + 1); |
190 return path.mid (lastpos + 1); |
188 |
191 |
189 return path; |
192 return path; |
190 } |
193 } |
191 |
194 |
192 QString DocumentManager::findDocumentPath (QString relativePath, bool subdirs) |
195 QString DocumentManager::findDocumentPath (QString relativePath) |
193 { |
196 { |
194 // LDraw models use backslashes as path separators. Replace those into forward slashes for Qt. |
197 return m_libraries.find(relativePath); |
195 relativePath.replace ("\\", "/"); |
|
196 |
|
197 // Try find it relative to other currently open documents. We want a file in the immediate vicinity of a current |
|
198 // part model to override stock LDraw stuff. |
|
199 QString relativeTopDir = Basename (Dirname (relativePath)); |
|
200 |
|
201 for (LDDocument* document : m_documents) |
|
202 { |
|
203 QString partpath = format ("%1/%2", Dirname (document->fullPath()), relativePath); |
|
204 QFileInfo fileinfo (partpath); |
|
205 |
|
206 if (fileinfo.exists()) |
|
207 { |
|
208 // Ensure we don't mix subfiles and 48-primitives with non-subfiles and non-48 |
|
209 QString partTopDir = Basename (Dirname (partpath)); |
|
210 |
|
211 for (QString subdir : specialSubdirectories) |
|
212 { |
|
213 if ((partTopDir == subdir) != (relativeTopDir == subdir)) |
|
214 goto skipthis; |
|
215 } |
|
216 |
|
217 return partpath; |
|
218 } |
|
219 skipthis: |
|
220 continue; |
|
221 } |
|
222 |
|
223 if (QFileInfo::exists (relativePath)) |
|
224 return relativePath; |
|
225 |
|
226 // Try with just the LDraw path first |
|
227 QString fullPath = format ("%1" DIRSLASH "%2", configuration().lDrawPath(), relativePath); |
|
228 |
|
229 if (QFileInfo::exists (fullPath)) |
|
230 return fullPath; |
|
231 |
|
232 if (subdirs) |
|
233 { |
|
234 // Look in sub-directories: parts and p. Also look in the download path, since that's where we download parts |
|
235 // from the PT to. |
|
236 QStringList dirs = { configuration().lDrawPath(), configuration().downloadFilePath() }; |
|
237 for (const QString& topdir : dirs) |
|
238 { |
|
239 for (const QString& subdir : QStringList ({ "parts", "p" })) |
|
240 { |
|
241 fullPath = format ("%1" DIRSLASH "%2" DIRSLASH "%3", topdir, subdir, relativePath); |
|
242 |
|
243 if (QFile::exists (fullPath)) |
|
244 return fullPath; |
|
245 } |
|
246 } |
|
247 } |
|
248 |
|
249 // Did not find the file. |
|
250 return ""; |
|
251 } |
|
252 |
|
253 QFile* DocumentManager::openLDrawFile (QString relpath, bool subdirs, QString* pathpointer) |
|
254 { |
|
255 print ("Opening %1...\n", relpath); |
|
256 QString path = findDocumentPath (relpath, subdirs); |
|
257 |
|
258 if (pathpointer) |
|
259 *pathpointer = path; |
|
260 |
|
261 if (path.isEmpty()) |
|
262 return nullptr; |
|
263 |
|
264 QFile* fp = new QFile (path); |
|
265 |
|
266 if (fp->open (QIODevice::ReadOnly)) |
|
267 return fp; |
|
268 |
|
269 fp->deleteLater(); |
|
270 return nullptr; |
|
271 } |
198 } |
272 |
199 |
273 void DocumentManager::loadFileContents(QIODevice* input, Model& model, int* numWarnings, bool* ok) |
200 void DocumentManager::loadFileContents(QIODevice* input, Model& model, int* numWarnings, bool* ok) |
274 { |
201 { |
275 if (numWarnings) |
202 if (numWarnings) |
301 bool* aborted) |
228 bool* aborted) |
302 { |
229 { |
303 // Convert the file name to lowercase when searching because some parts contain subfile |
230 // Convert the file name to lowercase when searching because some parts contain subfile |
304 // subfile references with uppercase file names. I'll assume here that the library will always |
231 // subfile references with uppercase file names. I'll assume here that the library will always |
305 // use lowercase file names for the part files. |
232 // use lowercase file names for the part files. |
306 QFile* fp; |
|
307 QString fullpath; |
233 QString fullpath; |
308 |
234 |
309 if (search) |
235 if (search) |
310 { |
236 { |
311 fp = openLDrawFile (path.toLower(), true, &fullpath); |
237 print ("Opening %1...\n", path.toLower()); |
|
238 fullpath = findDocumentPath(path.toLower()); |
|
239 |
|
240 if (fullpath.isEmpty()) |
|
241 return nullptr; |
312 } |
242 } |
313 else |
243 else |
314 { |
244 { |
315 fp = new QFile (path); |
|
316 fullpath = path; |
245 fullpath = path; |
317 |
246 } |
318 if (not fp->open (QIODevice::ReadOnly)) |
247 |
319 { |
248 QFile file {fullpath}; |
320 delete fp; |
249 |
321 return nullptr; |
250 if (not file.open(QIODevice::ReadOnly)) |
322 } |
|
323 } |
|
324 |
|
325 if (not fp) |
|
326 return nullptr; |
251 return nullptr; |
327 |
252 |
328 LDDocument* load = (fileToOverride ? fileToOverride : m_window->newDocument (implicit)); |
253 LDDocument* load = (fileToOverride ? fileToOverride : m_window->newDocument (implicit)); |
329 load->setFullPath (fullpath); |
254 load->setFullPath (fullpath); |
330 load->setName (LDDocument::shortenName (load->fullPath())); |
255 load->setName (LDDocument::shortenName (load->fullPath())); |