@@ -147,8 +147,11 @@ class Warning(widget.OWWidget.Warning):
147
147
class Error (widget .OWWidget .Error ):
148
148
file_not_found = Msg ("File not found." )
149
149
missing_reader = Msg ("Missing reader." )
150
+ select_file_type = Msg ("Select file type." )
150
151
sheet_error = Msg ("Error listing available sheets." )
151
152
unknown = Msg ("Read error:\n {}" )
153
+ unknown_select = Msg (
154
+ "Read error, possibly due to incorrect choice of file type:\n {}" )
152
155
153
156
UserAdviceMessages = [
154
157
widget .Message (
@@ -264,7 +267,7 @@ def package(w):
264
267
self .reader_combo = QComboBox (self )
265
268
self .reader_combo .setSizePolicy (Policy .Expanding , Policy .Fixed )
266
269
self .reader_combo .setMinimumSize (QSize (100 , 1 ))
267
- self .reader_combo .activated [int ].connect (self .select_reader )
270
+ self .reader_combo .activated [int ].connect (self .on_reader_change )
268
271
269
272
box .layout ().addWidget (self .reader_combo )
270
273
layout .addWidget (box , 0 , 1 )
@@ -327,6 +330,10 @@ def select_sheet(self):
327
330
self .recent_paths [0 ].sheet = self .sheet_combo .currentText ()
328
331
self .load_data ()
329
332
333
+ def on_reader_change (self , n ):
334
+ self .select_reader (n )
335
+ self .load_data ()
336
+
330
337
def select_reader (self , n ):
331
338
if self .source != self .LOCAL_FILE :
332
339
return # ignore for URL's
@@ -335,14 +342,11 @@ def select_reader(self, n):
335
342
path = self .recent_paths [0 ]
336
343
if n == 0 : # default
337
344
path .file_format = None
338
- self .load_data ()
339
345
elif n <= len (self .available_readers ):
340
346
reader = self .available_readers [n - 1 ]
341
347
path .file_format = reader .qualified_name ()
342
- self .load_data ()
343
348
else : # the rest include just qualified names
344
349
path .file_format = self .reader_combo .itemText (n )
345
- self .load_data ()
346
350
347
351
def _url_set (self ):
348
352
index = self .url_combo .currentIndex ()
@@ -373,7 +377,9 @@ def browse_file(self, in_demos=False):
373
377
else :
374
378
start_file = self .last_path () or os .path .expanduser ("~/" )
375
379
376
- filename , reader , _ = open_filename_dialog (start_file , None , self .available_readers )
380
+ filename , reader , _ = open_filename_dialog (
381
+ start_file , None , self .available_readers ,
382
+ add_all = "*" )
377
383
if not filename :
378
384
return
379
385
self .add_path (filename )
@@ -415,20 +421,20 @@ def _try_load(self):
415
421
if not url :
416
422
return self .Information .no_file_selected
417
423
418
- def mark_problematic_reader ():
419
- self .reader_combo .setItemData (self .reader_combo .currentIndex (),
420
- QBrush (Qt .red ), Qt .ForegroundRole )
421
-
422
424
try :
423
425
self .reader = self ._get_reader () # also sets current reader index
424
426
assert self .reader is not None
425
427
except MissingReaderException :
426
- mark_problematic_reader ()
427
- return self .Error .missing_reader
428
+ if self .reader_combo .currentIndex () > 0 :
429
+ return self .Error .missing_reader
430
+ else :
431
+ return self .Error .select_file_type
428
432
except Exception as ex :
429
- mark_problematic_reader ()
430
433
log .exception (ex )
431
- return lambda x = ex : self .Error .unknown (str (x ))
434
+ if self .reader_combo .currentIndex () > 0 :
435
+ return lambda x = ex : self .Error .unknown (str (x ))
436
+ else :
437
+ return lambda x = ex : self .Error .unknown_select (str (x ))
432
438
433
439
try :
434
440
self ._update_sheet_combo ()
@@ -439,7 +445,6 @@ def mark_problematic_reader():
439
445
try :
440
446
data = self .reader .read ()
441
447
except Exception as ex :
442
- mark_problematic_reader ()
443
448
log .exception (ex )
444
449
return lambda x = ex : self .Error .unknown (str (x ))
445
450
if warnings :
@@ -455,9 +460,25 @@ def mark_problematic_reader():
455
460
return None
456
461
457
462
def _get_reader (self ) -> FileFormat :
463
+ """
464
+ Get the reader for the current file.
465
+
466
+ For local files, this also observes the stored settings and the reader
467
+ combo, as follows:
468
+
469
+ 1. If the file format is known (from stored settings), use it and set
470
+ the reader combo to the corresponding index (as in settings)
471
+ 2. Otherwise, detect it from the extension and set the combo to
472
+ Auto detect, overriding any previous user-set choice
473
+ 3. Otherwise, use the current combo state.
474
+
475
+ Returns:
476
+ FileFormat: reader instance
477
+ """
458
478
if self .source == self .LOCAL_FILE :
459
479
path = self .last_path ()
460
480
self .reader_combo .setEnabled (True )
481
+
461
482
if self .recent_paths and self .recent_paths [0 ].file_format :
462
483
qname = self .recent_paths [0 ].file_format
463
484
qname_index = {r .qualified_name (): i for i , r in enumerate (self .available_readers )}
@@ -471,11 +492,22 @@ def _get_reader(self) -> FileFormat:
471
492
try :
472
493
reader_class = class_from_qualified_name (qname )
473
494
except Exception as ex :
474
- raise MissingReaderException (f'Can not find reader "{ qname } "' ) from ex
495
+ raise MissingReaderException (f'Can not fdind reader "{ qname } "' ) from ex
475
496
reader = reader_class (path )
497
+
476
498
else :
477
- self .reader_combo .setCurrentIndex (0 )
478
- reader = FileFormat .get_reader (path )
499
+ old_idx = self .reader_combo .currentIndex ()
500
+ try :
501
+ self .reader_combo .setCurrentIndex (0 )
502
+ reader = FileFormat .get_reader (path )
503
+ except MissingReaderException :
504
+ if old_idx == 0 :
505
+ raise
506
+ # Set the path for the current file format,
507
+ # and repeat the call to return the corresponding reader
508
+ self .select_reader (old_idx )
509
+ return self ._get_reader ()
510
+
479
511
if self .recent_paths and self .recent_paths [0 ].sheet :
480
512
reader .select_sheet (self .recent_paths [0 ].sheet )
481
513
return reader
@@ -504,12 +536,21 @@ def _select_active_sheet(self):
504
536
self .sheet_combo .setCurrentIndex (0 )
505
537
506
538
def _initialize_reader_combo (self ):
507
- self .reader_combo .clear ()
508
- filters = [format_filter (f ) for f in self .available_readers ]
509
- self .reader_combo .addItems ([DEFAULT_READER_TEXT ] + filters )
510
- self .reader_combo .setCurrentIndex (0 )
511
- self .reader_combo .setDisabled (True )
512
- # additional readers may be added in self._get_reader()
539
+ # Reset to initial state without losing the current index or
540
+ # emitting any signals.
541
+ combo = self .reader_combo
542
+ if not combo .count ():
543
+ filters = [format_filter (f ) for f in self .available_readers ]
544
+ combo .addItems ([DEFAULT_READER_TEXT ] + filters )
545
+ combo .setCurrentIndex (0 )
546
+ else :
547
+ # additional readers may be added in self._get_reader()
548
+ n = len (self .available_readers ) + 1
549
+ if combo .currentIndex () >= n :
550
+ combo .setCurrentIndex (0 )
551
+ while combo .count () > n :
552
+ combo .removeItem (combo .count () - 1 )
553
+ combo .setDisabled (True )
513
554
514
555
@staticmethod
515
556
def _describe (table ):
0 commit comments