src/file.cpp

changeset 370
843b3dbbd849
parent 363
75583c9f289d
child 371
e8ef9fb4721b
equal deleted inserted replaced
369:0060d11e4991 370:843b3dbbd849
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 <QMessageBox> 19 #include <QMessageBox>
20 #include <QFileDialog> 20 #include <QFileDialog>
21 #include <qprogressbar.h>
22 #include <QDir> 21 #include <QDir>
23 #include <QThread> 22 #include <QApplication>
24 23
25 #include <stdlib.h> 24 #include <stdlib.h>
26 #include "common.h" 25 #include "common.h"
27 #include "config.h" 26 #include "config.h"
28 #include "file.h" 27 #include "file.h"
43 // ============================================================================= 42 // =============================================================================
44 namespace LDPaths 43 namespace LDPaths
45 { 44 {
46 static str pathError; 45 static str pathError;
47 46
48 struct 47 struct {
49 {
50 str LDConfigPath; 48 str LDConfigPath;
51 str partsPath, primsPath; 49 str partsPath, primsPath;
52 } pathInfo; 50 } pathInfo;
53 51
54 void initPaths () 52 void initPaths() {
55 { 53 if( !tryConfigure( io_ldpath )) {
56 if( !tryConfigure ( io_ldpath ))
57 {
58 LDrawPathDialog dlg (false); 54 LDrawPathDialog dlg (false);
59 55
60 if( !dlg.exec () ) 56 if( !dlg.exec () )
61 exit( 0 ); 57 exit( 0 );
62 58
63 io_ldpath = dlg.filename(); 59 io_ldpath = dlg.filename();
64 } 60 }
65 } 61 }
66 62
67 bool tryConfigure( str path ) 63 bool tryConfigure( str path ) {
68 {
69 QDir dir; 64 QDir dir;
70 65
71 if( !dir.cd( path )) 66 if( !dir.cd( path )) {
72 {
73 pathError = "Directory does not exist."; 67 pathError = "Directory does not exist.";
74 return false; 68 return false;
75 } 69 }
76 70
77 QStringList mustHave = { "LDConfig.ldr", "parts", "p" }; 71 QStringList mustHave = { "LDConfig.ldr", "parts", "p" };
78 QStringList contents = dir.entryList( mustHave ); 72 QStringList contents = dir.entryList( mustHave );
79 73
80 if (contents.size () != mustHave.size ()) { 74 if( contents.size() != mustHave.size() ) {
81 pathError = "Not an LDraw directory! Must<br />have LDConfig.ldr, parts/ and p/."; 75 pathError = "Not an LDraw directory! Must<br />have LDConfig.ldr, parts/ and p/.";
82 return false; 76 return false;
83 } 77 }
84 78
85 pathInfo.partsPath = fmt( "%1" DIRSLASH "parts", path ); 79 pathInfo.partsPath = fmt( "%1" DIRSLASH "parts", path );
153 147
154 // ============================================================================= 148 // =============================================================================
155 File* openLDrawFile (str relpath, bool subdirs) { 149 File* openLDrawFile (str relpath, bool subdirs) {
156 print( "%1: Try to open %2\n", __func__, relpath ); 150 print( "%1: Try to open %2\n", __func__, relpath );
157 File* f = new File; 151 File* f = new File;
152 str fullPath;
158 153
159 // LDraw models use Windows-style path separators. If we're not on Windows, 154 // LDraw models use Windows-style path separators. If we're not on Windows,
160 // replace the path separator now before opening any files. 155 // replace the path separator now before opening any files.
161 #ifndef WIN32 156 #ifndef WIN32
162 relpath.replace( "\\", "/" ); 157 relpath.replace( "\\", "/" );
163 #endif // WIN32 158 #endif // WIN32
164 159
165 if( g_curfile ) 160 if( g_curfile ) {
166 {
167 // First, try find the file in the current model's file path. We want a file 161 // First, try find the file in the current model's file path. We want a file
168 // in the immediate vicinity of the current model to override stock LDraw stuff. 162 // in the immediate vicinity of the current model to override stock LDraw stuff.
169 str partpath = fmt ("%1" DIRSLASH "%2", dirname (g_curfile->name ()), relpath); 163 str partpath = fmt ("%1" DIRSLASH "%2", dirname (g_curfile->name ()), relpath);
170 164
171 if (f->open (partpath, File::Read)) 165 if (f->open (partpath, File::Read)) {
172 return f; 166 return f; }}
173 }
174 167
175 if (f->open (relpath, File::Read)) 168 if (f->open (relpath, File::Read))
176 return f; 169 return f;
177 170
178 str fullPath; 171 // Try with just the LDraw path first
179 if( io_ldpath.value.length() > 0 ) 172 fullPath = fmt ("%1" DIRSLASH "%2", io_ldpath, relpath);
180 { 173
181 // Try with just the LDraw path first 174 if( f->open( fullPath, File::Read ))
182 fullPath = fmt ("%1" DIRSLASH "%2", io_ldpath, relpath); 175 return f;
183 176
184 if( f->open( fullPath, File::Read )) 177 if( subdirs ) {
185 return f; 178 // Look in sub-directories: parts and p
186 179 for( auto subdir : initlist<const str>({ "parts", "p" })) {
187 if( subdirs ) 180 fullPath = fmt ("%1" DIRSLASH "%2" DIRSLASH "%3",
188 { 181 io_ldpath, subdir, relpath);
189 // Look in sub-directories: parts and p 182
190 for( auto subdir : initlist<const str>({ "parts", "p" })) 183 if (f->open (fullPath, File::Read))
191 { 184 return f; }}
192 fullPath = fmt ("%1" DIRSLASH "%2" DIRSLASH "%3",
193 io_ldpath, subdir, relpath);
194
195 if (f->open (fullPath, File::Read))
196 return f;
197 }
198 }
199 }
200 185
201 // Did not find the file. 186 // Did not find the file.
187 print( "could not find %1\n", relpath );
202 delete f; 188 delete f;
203 return null; 189 return null;
204 } 190 }
205 191
206 // ============================================================================= 192 // =============================================================================
207 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 193 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
208 // ============================================================================= 194 // =============================================================================
209 void FileLoader::work() 195 void FileLoader::start() {
210 {
211 setDone( false ); 196 setDone( false );
212 setProgress( 0 ); 197 setProgress( 0 );
213 abortflag = false; 198 abortflag = false;
214 199
215 for( str line : *PROP_NAME( file )) { 200 if( concurrent() ) {
201 // Show a progress dialog if we're loading the main file here and move
202 // the actual work to a separate thread as this can be a rather intensive
203 // operation and if we don't respond quickly enough, the program can be
204 // deemed inresponsive.. which is a bad thing.
205 dlg = new OpenProgressDialog (g_win);
206 dlg->setNumLines( lines().size() );
207 dlg->setModal( true );
208 dlg->show();
209
210 // Connect the loader in so we can show updates
211 connect( this, SIGNAL( workDone() ), dlg, SLOT( accept() )); }
212 else
213 dlg = null;
214
215 work( 0 );
216 }
217
218 void FileLoader::work( ulong i ) {
219 print( "%1: %2\n", this, i );
220
221 if( abortflag ) {
222 // We were flagged for abortion, so abort.
223 for( LDObject* obj : m_objs )
224 delete obj;
225
226 m_objs.clear();
227 abortflag = false;
228 return;
229 }
230
231 ulong max = i + 300;
232 for( ; i < max && i < lines().size(); ++i ) {
233 str line = lines()[i];
234
216 // Trim the trailing newline 235 // Trim the trailing newline
217 qchar c; 236 qchar c;
218 while(( c = line[line.length () - 1] ) == '\n' || c == '\r' ) 237 while(( c = line[line.length () - 1] ) == '\n' || c == '\r' )
219 line.chop( 1 ); 238 line.chop( 1 );
220 239
221 LDObject* obj = parseLine( line ); 240 LDObject* obj = parseLine( line );
222 241
223 // Check for parse errors and warn about tthem 242 // Check for parse errors and warn about tthem
224 if( obj->getType () == LDObject::Gibberish ) 243 if( obj->getType () == LDObject::Gibberish ) {
225 {
226 log( "Couldn't parse line #%1: %2", m_progress + 1, static_cast<LDGibberish*> (obj)->reason ); 244 log( "Couldn't parse line #%1: %2", m_progress + 1, static_cast<LDGibberish*> (obj)->reason );
227 log( "- Line was: %1", line ); 245
228 246 if( m_warningsPointer ) {
229 if( m_warningsPointer ) 247 ( *m_warningsPointer )++; }}
230 ( *m_warningsPointer )++;
231 }
232 248
233 m_objs << obj; 249 m_objs << obj;
234 m_progress++; 250 setProgress( i );
235 emit progressUpdate( m_progress ); 251
236 252 if( concurrent() )
237 if( abortflag ) 253 dlg->updateProgress( i );
238 { 254 }
239 // We were flagged for abortion, so abort. 255
240 for( LDObject* obj : m_objs ) 256 if( i >= lines().size() - 1 ) {
241 delete obj; 257 emit workDone();
242 258 setDone( true ); }
243 m_objs.clear(); 259
244 return; 260 if( !done() ) {
245 } 261 if( concurrent() )
246 } 262 QMetaObject::invokeMethod( this, "work", Qt::QueuedConnection, Q_ARG( ulong, i + 1 ));
247 263 else
248 emit workDone(); 264 work( i + 1 );
249 m_done = true; 265 }
250 } 266 }
251 267
252 // ============================================================================= 268 // =============================================================================
253 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 269 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
254 // ============================================================================= 270 // =============================================================================
258 g_aborted = false; 274 g_aborted = false;
259 275
260 if( numWarnings ) 276 if( numWarnings )
261 *numWarnings = 0; 277 *numWarnings = 0;
262 278
279 // Calculate the amount of lines
280 for( str line : *f )
281 lines << line;
282 f->rewind();
283
263 FileLoader* loader = new FileLoader; 284 FileLoader* loader = new FileLoader;
264 loader->setFile( f );
265 loader->setWarningsPointer( numWarnings ); 285 loader->setWarningsPointer( numWarnings );
266 286 loader->setLines( lines );
267 // Calculate the amount of lines 287 loader->setConcurrent( g_loadingMainFile );
268 ulong numLines = 0; 288 loader->start();
269 for( str line : *f ) 289
270 numLines++; 290 while( loader->done() == false )
271 291 qApp->processEvents();
272 f->rewind();
273
274 if (g_loadingMainFile)
275 {
276 // Show a progress dialog if we're loading the main file here and move
277 // the actual work to a separate thread as this can be a rather intensive
278 // operation and if we don't respond quickly enough, the program can be
279 // deemed inresponsive.. which is a bad thing.
280
281 // Init the thread and move the loader into it
282 QThread* loaderThread = new QThread;
283 QObject::connect( loaderThread, SIGNAL( started() ), loader, SLOT( work() ));
284 QObject::connect( loaderThread, SIGNAL( finished() ), loader, SLOT( deleteLater() ));
285 loader->moveToThread (loaderThread);
286 loaderThread->start ();
287
288 // Now create a progress prompt for the operation
289 OpenProgressDialog* dlg = new OpenProgressDialog (g_win);
290 dlg->setNumLines( numLines );
291
292 // Connect the loader in so we can show updates
293 QObject::connect( loader, SIGNAL( progressUpdate( int )), dlg, SLOT( updateProgress( int )));
294 QObject::connect( loader, SIGNAL( workDone() ), dlg, SLOT( accept() ));
295
296 // Show the prompt. If the user hits cancel, tell the loader to abort.
297 if( !dlg->exec() )
298 {
299 loader->abortflag = true;
300 g_aborted = true;
301 }
302 } else
303 loader->work();
304 292
305 // If we wanted the success value, supply that now 293 // If we wanted the success value, supply that now
306 if( ok ) 294 if( ok )
307 *ok = loader->done(); 295 *ok = loader->done();
308 296
309 // If the loader was done, return the objects it generated 297 objs = loader->objs();
310 if( loader->done() )
311 objs = loader->objs();
312
313 return objs; 298 return objs;
314 } 299 }
315 300
316 // ============================================================================= 301 // =============================================================================
317 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 302 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
325 if( search ) 310 if( search )
326 f = openLDrawFile (path.toLower (), true); 311 f = openLDrawFile (path.toLower (), true);
327 else { 312 else {
328 f = new File( path, File::Read ); 313 f = new File( path, File::Read );
329 314
330 if( !*f ) 315 if( !*f ) {
331 {
332 delete f; 316 delete f;
333 f = null; 317 return null; }}
334 }
335 }
336 318
337 if( !f ) 319 if( !f )
338 return null; 320 return null;
339 321
340 LDOpenFile* oldLoad = g_curfile; 322 LDOpenFile* oldLoad = g_curfile;
784 } 766 }
785 767
786 // ============================================================================= 768 // =============================================================================
787 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 769 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
788 // ============================================================================= 770 // =============================================================================
789 LDOpenFile* getFile( str fname ) 771 LDOpenFile* getFile( str filename )
790 { 772 {
791 // Try find the file in the list of loaded files 773 // Try find the file in the list of loaded files
792 LDOpenFile* load = findLoadedFile( fname ); 774 LDOpenFile* load = findLoadedFile( filename );
793 775
794 // If it's not loaded, try open it 776 // If it's not loaded, try open it
795 if( !load ) 777 if( !load )
796 load = openDATFile( fname, true ); 778 load = openDATFile( filename, true );
797 779
798 return load; 780 return load;
799 } 781 }
800 782
801 // ============================================================================= 783 // =============================================================================

mercurial