src/documentloader.cpp

changeset 1288
d1e45f90654b
parent 1287
f1da43b7f5c6
child 1289
ec5a38d19cf5
equal deleted inserted replaced
1287:f1da43b7f5c6 1288:d1e45f90654b
1 /*
2 * LDForge: LDraw parts authoring CAD
3 * Copyright (C) 2013 - 2017 Teemu Piippo
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
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/>.
17 */
18
19 #include "documentloader.h"
20 #include "lddocument.h"
21 #include "linetypes/modelobject.h"
22 #include "mainwindow.h"
23 #include "dialogs/openprogressdialog.h"
24
25 DocumentLoader::DocumentLoader(
26 Model* model,
27 LDHeader& header,
28 bool onForeground,
29 QObject *parent,
30 ) :
31 QObject {parent},
32 _model {model},
33 _header {header},
34 m_isOnForeground {onForeground} {}
35
36 bool DocumentLoader::hasAborted()
37 {
38 return m_hasAborted;
39 }
40
41 bool DocumentLoader::isDone() const
42 {
43 return m_isDone;
44 }
45
46 int DocumentLoader::progress() const
47 {
48 return m_progress;
49 }
50
51 int DocumentLoader::warningCount() const
52 {
53 return m_warningCount;
54 }
55
56 bool DocumentLoader::isOnForeground() const
57 {
58 return m_isOnForeground;
59 }
60
61 const QVector<LDObject*>& DocumentLoader::objects() const
62 {
63 return _model->objects();
64 }
65
66 void DocumentLoader::read (QIODevice* fp)
67 {
68 if (fp and fp->isOpen())
69 {
70 while (not fp->atEnd())
71 m_lines << QString::fromUtf8(fp->readLine()).simplified();
72 }
73 }
74
75 void DocumentLoader::start()
76 {
77 m_isDone = false;
78 m_progress = 0;
79 m_hasAborted = false;
80
81 if (isOnForeground())
82 {
83 // Show a progress dialog if we're loading the main lddocument.here so we can show progress updates and keep the
84 // WM posted that we're still here.
85 m_progressDialog = new OpenProgressDialog(qobject_cast<QWidget*>(parent()));
86 m_progressDialog->setNumLines (countof(m_lines));
87 m_progressDialog->setModal (true);
88 m_progressDialog->show();
89 connect (this, SIGNAL (workDone()), m_progressDialog, SLOT (accept()));
90 connect (m_progressDialog, SIGNAL (rejected()), this, SLOT (abort()));
91 }
92 else
93 {
94 m_progressDialog = nullptr;
95 }
96
97 // Parse the header
98 while (m_progress < m_lines.size())
99 {
100 const QString& line = m_lines[m_progress];
101
102 if (not line.isEmpty())
103 {
104 if (line.startsWith("0"))
105 {
106 if (m_progress == 0)
107 {
108 _header.description = line.mid(1).simplified();
109 }
110 else if (line.startsWith("0 !LDRAW_ORG"))
111 {
112 QStringList tokens = line.mid(strlen("0 !LDRAW_ORG"));
113 }
114 else if (line.startsWith("0 BFC"))
115 {
116 ...;
117 }
118 else
119 {
120 _model->addFromString(line);
121 }
122 m_progress += 1;
123 }
124 else
125 {
126 break;
127 }
128 }
129 }
130
131 // Begin working
132 work (0);
133 }
134
135 void DocumentLoader::work (int i)
136 {
137 // User wishes to abort, so stop here now.
138 if (hasAborted())
139 {
140 m_isDone = true;
141 return;
142 }
143
144 // Parse up to 200 lines per iteration
145 int max = i + 200;
146
147 bool invertNext = false;
148
149 for (; i < max and i < (int) countof(m_lines); ++i)
150 {
151 const QString& line = m_lines[i];
152
153 if (line == "0 BFC INVERTNEXT")
154 {
155 invertNext = true;
156 continue;
157 }
158
159 LDObject* obj = _model->addFromString(line);
160
161 // Check for parse errors and warn about them
162 if (obj->type() == LDObjectType::Error)
163 {
164 emit parseErrorMessage(format(tr("Couldn't parse line #%1: %2"), progress() + 1, static_cast<LDError*> (obj)->reason()));
165 ++m_warningCount;
166 }
167
168 if (invertNext and obj->type() == LDObjectType::SubfileReference)
169 obj->setInverted(true);
170
171 invertNext = false;
172 }
173
174 m_progress = i;
175
176 if (m_progressDialog)
177 m_progressDialog->setProgress (i);
178
179 if (i >= countof(m_lines) - 1)
180 {
181 emit workDone();
182 m_isDone = true;
183 }
184 else
185 {
186 // If we have a dialog to show progress output to, we cannot just call work() again immediately as the dialog
187 // needs to be updated as well. Thus, we take a detour through the event loop by using the meta-object system.
188 //
189 // This terminates the loop here and control goes back to the function which called the file loader. It will
190 // keep processing the event loop until we're ready (see loadFileContents), thus the event loop will eventually
191 // catch the invokation we throw here and send us back.
192 if (isOnForeground())
193 QMetaObject::invokeMethod (this, "work", Qt::QueuedConnection, Q_ARG (int, i));
194 else
195 work (i);
196 }
197 }
198
199 void DocumentLoader::abort()
200 {
201 m_hasAborted = true;
202 }

mercurial