src/documentmanager.cpp

changeset 1308
dcc8c02530c2
parent 1306
be85306198a2
child 1318
568fcfc6da71
equal deleted inserted replaced
1307:adb9d32a1426 1308:dcc8c02530c2
15 * You should have received a copy of the GNU General Public License 15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */ 17 */
18 18
19 #include <QApplication> 19 #include <QApplication>
20 #include <QDir>
20 #include <QFileInfo> 21 #include <QFileInfo>
21 #include <QMessageBox> 22 #include <QMessageBox>
22 #include "documentmanager.h" 23 #include "documentmanager.h"
23 #include "lddocument.h" 24 #include "lddocument.h"
24 #include "mainwindow.h" 25 #include "mainwindow.h"
195 return path.mid (lastpos + 1); 196 return path.mid (lastpos + 1);
196 197
197 return path; 198 return path;
198 } 199 }
199 200
200 QString DocumentManager::findDocumentPath (QString relativePath, bool subdirs) 201 QString DocumentManager::findDocument(QString name) const
201 { 202 {
202 // LDraw models use backslashes as path separators. Replace those into forward slashes for Qt. 203 name = name.replace("\\", "/");
203 relativePath.replace ("\\", "/"); 204
204 205 for (const Library& library : ::config->libraries())
205 // Try find it relative to other currently open documents. We want a file in the immediate vicinity of a current 206 {
206 // part model to override stock LDraw stuff. 207 for (const QString& subdirectory : {"parts", "p"})
207 QString relativeTopDir = Basename (Dirname (relativePath)); 208 {
208 209 QDir dir {library.path + "/" + subdirectory};
209 for (LDDocument* document : m_documents) 210
210 { 211 if (dir.exists(name))
211 QString partpath = format ("%1/%2", Dirname (document->fullPath()), relativePath); 212 return QDir::cleanPath(dir.filePath(name));
212 QFileInfo fileinfo (partpath); 213 }
213 214 }
214 if (fileinfo.exists()) 215
215 { 216 return {};
216 // Ensure we don't mix subfiles and 48-primitives with non-subfiles and non-48 217 }
217 QString partTopDir = Basename (Dirname (partpath)); 218
218 219 void DocumentManager::printParseErrorMessage(QString message)
219 for (QString subdir : specialSubdirectories) 220 {
221 print(message);
222 }
223
224 LDDocument* DocumentManager::openDocument(
225 QString path,
226 bool search,
227 bool implicit,
228 LDDocument* fileToOverride
229 ) {
230 if (search and not QFileInfo {path}.exists())
231 {
232 // Convert the file name to lowercase when searching because some parts contain subfile
233 // subfile references with uppercase file names. I'll assume here that the library will
234 // always use lowercase file names for the part files.
235 path = this->findDocument(path.toLower());
236 }
237
238 QFile file {path};
239
240 if (file.open(QIODevice::ReadOnly))
241 {
242 LDDocument* load = fileToOverride;
243
244 if (fileToOverride == nullptr)
245 load = m_window->newDocument(implicit);
246
247 load->setFullPath(path);
248 load->setName(LDDocument::shortenName(path));
249
250 // Loading the file shouldn't count as actual edits to the document.
251 load->history()->setIgnoring (true);
252
253 Parser parser {file};
254 Winding winding = NoWinding;
255 load->header = parser.parseHeader(winding);
256 load->setWinding(winding);
257 parser.parseBody(*load);
258 file.close();
259
260 if (m_loadingMainFile)
261 {
262 int numWarnings = 0;
263
264 for (LDObject* object : load->objects())
220 { 265 {
221 if ((partTopDir == subdir) != (relativeTopDir == subdir)) 266 if (object->type() == LDObjectType::Error)
222 goto skipthis; 267 numWarnings += 1;
223 } 268 }
224 269
225 return partpath; 270 m_window->changeDocument(load);
226 } 271 print(tr("File %1 opened successfully (%2 errors)."), load->name(), numWarnings);
227 skipthis: 272 }
228 continue; 273
229 } 274 load->history()->setIgnoring (false);
230 275 return load;
231 if (QFileInfo::exists (relativePath)) 276 }
232 return relativePath; 277 else
233 278 {
234 // Try with just the LDraw path first
235 QString fullPath = format ("%1" DIRSLASH "%2", m_config->lDrawPath(), relativePath);
236
237 if (QFileInfo::exists (fullPath))
238 return fullPath;
239
240 if (subdirs)
241 {
242 // Look in sub-directories: parts and p. Also look in the download path, since that's where we download parts
243 // from the PT to.
244 QStringList dirs = { m_config->lDrawPath(), m_config->downloadFilePath() };
245 for (const QString& topdir : dirs)
246 {
247 for (const QString& subdir : QStringList ({ "parts", "p" }))
248 {
249 fullPath = format ("%1" DIRSLASH "%2" DIRSLASH "%3", topdir, subdir, relativePath);
250
251 if (QFile::exists (fullPath))
252 return fullPath;
253 }
254 }
255 }
256
257 // Did not find the file.
258 return "";
259 }
260
261 QFile* DocumentManager::openLDrawFile (QString relpath, bool subdirs, QString* pathpointer)
262 {
263 print ("Opening %1...\n", relpath);
264 QString path = findDocumentPath (relpath, subdirs);
265
266 if (pathpointer)
267 *pathpointer = path;
268
269 if (path.isEmpty())
270 return nullptr; 279 return nullptr;
271 280 }
272 QFile* fp = new QFile (path);
273
274 if (fp->open (QIODevice::ReadOnly))
275 return fp;
276
277 fp->deleteLater();
278 return nullptr;
279 }
280
281 void DocumentManager::printParseErrorMessage(QString message)
282 {
283 print(message);
284 }
285
286 LDDocument* DocumentManager::openDocument (QString path, bool search, bool implicit, LDDocument* fileToOverride)
287 {
288 // Convert the file name to lowercase when searching because some parts contain subfile
289 // subfile references with uppercase file names. I'll assume here that the library will always
290 // use lowercase file names for the part files.
291 QFile* fp;
292 QString fullpath;
293
294 if (search)
295 {
296 fp = openLDrawFile (path.toLower(), true, &fullpath);
297 }
298 else
299 {
300 fp = new QFile (path);
301 fullpath = path;
302
303 if (not fp->open (QIODevice::ReadOnly))
304 {
305 delete fp;
306 return nullptr;
307 }
308 }
309
310 if (not fp)
311 return nullptr;
312
313 LDDocument* load = (fileToOverride ? fileToOverride : m_window->newDocument (implicit));
314 load->setFullPath (fullpath);
315 load->setName (LDDocument::shortenName (load->fullPath()));
316
317 // Loading the file shouldn't count as actual edits to the document.
318 load->history()->setIgnoring (true);
319
320 int numWarnings;
321 Parser parser {*fp};
322 Winding winding = NoWinding;
323 load->header = parser.parseHeader(winding);
324 load->setWinding(winding);
325 parser.parseBody(*load);
326 fp->close();
327 fp->deleteLater();
328
329 if (m_loadingMainFile)
330 {
331 int numWarnings = 0;
332
333 for (LDObject* object : load->objects())
334 {
335 if (object->type() == LDObjectType::Error)
336 numWarnings += 1;
337 }
338
339 m_window->changeDocument (load);
340 print (tr ("File %1 parsed successfully (%2 errors)."), path, numWarnings);
341 }
342
343 load->history()->setIgnoring (false);
344 return load;
345 } 281 }
346 282
347 void DocumentManager::addRecentFile (QString path) 283 void DocumentManager::addRecentFile (QString path)
348 { 284 {
349 QStringList recentFiles = m_config->recentFiles(); 285 QStringList recentFiles = m_config->recentFiles();

mercurial