11import os .path
22
3- from AnyQt .QtWidgets import QFileDialog
4- from AnyQt .QtCore import Qt
3+ from AnyQt .QtWidgets import QFileDialog , QGridLayout , QWidget
54
65from Orange .data .table import Table
76from Orange .data .io import TabReader , CSVReader , PickleReader , ExcelReader
@@ -21,29 +20,27 @@ class OWSave(widget.OWWidget):
2120 settings_version = 2
2221
2322 writers = [TabReader , CSVReader , PickleReader , ExcelReader ]
24- filters = [f"{ w .DESCRIPTION } ({ w .EXTENSIONS [0 ]} )" for w in writers ]
23+ filters = [f"{ w .DESCRIPTION } (* { w .EXTENSIONS [0 ]} )" for w in writers ]
2524 filt_ext = {filter : w .EXTENSIONS [0 ] for filter , w in zip (filters , writers )}
2625 userhome = os .path .expanduser (f"~{ os .sep } " )
2726
2827 class Inputs :
2928 data = Input ("Data" , Table )
3029
3130 class Error (widget .OWWidget .Error ):
32- # This message is short to (almost) fit into the widget's width
33- unsupported_sparse = widget .Msg ("Format can't store sparse data ." )
31+ unsupported_sparse = widget . Msg ( "Use .pkl format for sparse data." )
32+ no_file_name = widget .Msg ("File name is not set ." )
3433 general_error = widget .Msg ("{}" )
3534
3635 class Warning (widget .OWWidget .Warning ):
37- no_file_name = widget .Msg ("Set the file name." )
38- general_error = widget .Msg ("{}" )
36+ ignored_flag = widget .Msg ("{} ignored for this format." )
3937
4038 want_main_area = False
4139 resizing_enabled = False
4240
4341 compress : bool
4442 add_type_annotations : bool
4543
46- filetype = Setting (0 )
4744 last_dir = Setting ("" )
4845 filter = Setting (filters [0 ])
4946 compress = Setting (False )
@@ -56,22 +53,31 @@ def __init__(self):
5653 self .filename = ""
5754 self .writer = self .writers [0 ]
5855
59- box = gui .vBox (self .controlArea , True )
60- box .layout ().setSpacing (8 )
61- self .lb_filename = gui .widgetLabel (box )
62- gui .checkBox (
63- box , self , "add_type_annotations" , "Save with type annotations" )
64- gui .checkBox (
65- box , self , "compress" , "Compress file (gzip)" )
66- self .bt_set_file = gui .button (
67- None , self , "Set File Name" , callback = self .set_file_name )
68- box .layout ().addWidget (self .bt_set_file , Qt .AlignRight )
69-
70- box = gui .vBox (self .controlArea , box = True )
71- box .layout ().setSpacing (8 )
72- gui .checkBox (
73- box , self , "auto_save" , "Autosave when receiving new data" )
74- self .bt_save = gui .button (box , self , "Save" , callback = self .save_file )
56+ grid = QGridLayout ()
57+ gui .widgetBox (self .controlArea , box = True , orientation = grid )
58+ grid .setSpacing (8 )
59+ self .bt_save = gui .button (None , self , "Save" , callback = self .save_file )
60+ grid .addWidget (self .bt_save , 0 , 0 )
61+ grid .addWidget (
62+ gui .button (None , self , "Save as ..." , callback = self .save_file_as ),
63+ 0 , 1 )
64+ grid .addWidget (
65+ gui .checkBox (None , self , "auto_save" ,
66+ "Autosave when receiving new data" ),
67+ 1 , 0 , 1 , 2 )
68+ grid .addWidget (QWidget (), 2 , 0 , 1 , 2 )
69+
70+ grid .addWidget (
71+ gui .checkBox (
72+ None , self , "add_type_annotations" ,
73+ "Save with type annotations" , callback = self ._update_controls ),
74+ 3 , 0 , 1 , 2 )
75+ grid .addWidget (
76+ gui .checkBox (
77+ None , self , "compress" , "Compress file (gzip)" ,
78+ callback = self ._update_controls ),
79+ 4 , 0 , 1 , 2 )
80+
7581 self .adjustSize ()
7682 self ._update_controls ()
7783
@@ -91,7 +97,7 @@ def dataset(self, data):
9197 f"Data set { self .data .name or '(no name)' } "
9298 f"with { len (self .data )} instances" )
9399
94- def set_file_name (self ):
100+ def save_file_as (self ):
95101 if self .filename :
96102 start_dir = self .filename
97103 else :
@@ -100,56 +106,69 @@ def set_file_name(self):
100106 data_name += self .filt_ext [self .filter ]
101107 start_dir = os .path .join (self .last_dir or self .userhome , data_name )
102108
103- dlg = QFileDialog (None , "Set File" , start_dir , ";;" .join (self .filters ))
104- dlg .setLabelText (dlg .Accept , "Select" )
105- dlg .setAcceptMode (dlg .AcceptSave )
106- dlg .setSupportedSchemes (["file" ])
107- dlg .selectNameFilter (self .filter )
108- if dlg .exec () == dlg .Rejected :
109+ filename , selected_filter = QFileDialog .getSaveFileName (
110+ self , "Save data" , start_dir , ";;" .join (self .filters ), self .filter )
111+ if not filename :
109112 return
110113
111- self .filename = dlg . selectedFiles ()[ 0 ]
112- self .last_dir = os .path .split (self . filename )[0 ]
113- self .filter = dlg . selectedNameFilter ()
114+ self .filename = filename
115+ self .last_dir = os .path .split (filename )[0 ]
116+ self .filter = selected_filter
114117 self .writer = self .writers [self .filters .index (self .filter )]
115118 self ._update_controls ()
119+ self .save_file ()
116120
117121 def save_file (self ):
122+ if not self .filename :
123+ self .save_file_as ()
124+ return
118125 self .Error .general_error .clear ()
119126 if not self ._can_save ():
120127 return
121- name = self .filename \
122- + ".gz" * self .writer .SUPPORT_COMPRESSED * self .compress
123128 try :
124- self .writer .write (name , self .data , self .add_type_annotations )
129+ self .writer .write (
130+ self ._fullname (), self .data , self .add_type_annotations )
125131 except IOError as err_value :
126132 self .Error .general_error (str (err_value ))
127133
134+ def _fullname (self ):
135+ return self .filename \
136+ + ".gz" * self .writer .SUPPORT_COMPRESSED * self .compress
137+
128138 def _update_controls (self ):
129- has_file = bool (self .filename )
130- self .lb_filename .setVisible (has_file )
131- self .Warning .no_file_name (shown = not has_file )
132139 if self .filename :
133- name = self .filename
134- if name .startswith (self .userhome ):
135- name = name [len (self .userhome ):]
136- self .lb_filename .setText (f"Save to: { name } " )
137-
138- self .controls .add_type_annotations .setVisible (
139- has_file and self .writer .OPTIONAL_TYPE_ANNOTATIONS )
140- self .controls .compress .setVisible (
141- has_file and self .writer .SUPPORT_COMPRESSED )
140+ self .bt_save .setText (
141+ f"Save as { os .path .split (self ._fullname ())[1 ]} " )
142+ else :
143+ self .bt_save .setText ("Save" )
144+ self .Error .no_file_name (shown = not self .filename )
142145
143146 self .Error .unsupported_sparse (
144147 shown = self .data is not None and self .data .is_sparse ()
145- and self .filename
146- and not self .writer .SUPPORT_SPARSE_DATA )
147- self .bt_save .setEnabled (self ._can_save ())
148+ and self .filename and not self .writer .SUPPORT_SPARSE_DATA )
149+
150+ if self .data is None or not self .filename :
151+ self .Warning .ignored_flag .clear ()
152+ else :
153+ no_compress = self .compress \
154+ and not self .writer .SUPPORT_COMPRESSED
155+ no_anotation = self .add_type_annotations \
156+ and not self .writer .OPTIONAL_TYPE_ANNOTATIONS
157+ ignored = [
158+ "" ,
159+ "Compression flag is" ,
160+ "Type annotation flag is" ,
161+ "Compression and type annotation flags are"
162+ ][no_compress + 2 * no_anotation ]
163+ self .Warning .ignored_flag (ignored , shown = bool (ignored ))
148164
149165 def _can_save (self ):
150- return self .data is not None \
151- and bool (self .filename ) \
152- and (not self .data .is_sparse () or self .writer .SUPPORT_SPARSE_DATA )
166+ return not (
167+ self .data is None
168+ or not self .filename
169+ or self .data .is_sparse () and not self .writer .SUPPORT_SPARSE_DATA
170+ or self .compress and not self .writer .SUPPORT_COMPRESSED
171+ )
153172
154173 def send_report (self ):
155174 self .report_data_brief (self .data )
0 commit comments