1
1
import os .path
2
2
3
- from AnyQt .QtWidgets import QFileDialog
4
- from AnyQt .QtCore import Qt
3
+ from AnyQt .QtWidgets import QFileDialog , QGridLayout , QWidget
5
4
6
5
from Orange .data .table import Table
7
6
from Orange .data .io import TabReader , CSVReader , PickleReader , ExcelReader
@@ -21,29 +20,27 @@ class OWSave(widget.OWWidget):
21
20
settings_version = 2
22
21
23
22
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 ]
25
24
filt_ext = {filter : w .EXTENSIONS [0 ] for filter , w in zip (filters , writers )}
26
25
userhome = os .path .expanduser (f"~{ os .sep } " )
27
26
28
27
class Inputs :
29
28
data = Input ("Data" , Table )
30
29
31
30
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 ." )
34
33
general_error = widget .Msg ("{}" )
35
34
36
35
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." )
39
37
40
38
want_main_area = False
41
39
resizing_enabled = False
42
40
43
41
compress : bool
44
42
add_type_annotations : bool
45
43
46
- filetype = Setting (0 )
47
44
last_dir = Setting ("" )
48
45
filter = Setting (filters [0 ])
49
46
compress = Setting (False )
@@ -56,22 +53,31 @@ def __init__(self):
56
53
self .filename = ""
57
54
self .writer = self .writers [0 ]
58
55
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
+
75
81
self .adjustSize ()
76
82
self ._update_controls ()
77
83
@@ -91,7 +97,7 @@ def dataset(self, data):
91
97
f"Data set { self .data .name or '(no name)' } "
92
98
f"with { len (self .data )} instances" )
93
99
94
- def set_file_name (self ):
100
+ def save_file_as (self ):
95
101
if self .filename :
96
102
start_dir = self .filename
97
103
else :
@@ -100,56 +106,69 @@ def set_file_name(self):
100
106
data_name += self .filt_ext [self .filter ]
101
107
start_dir = os .path .join (self .last_dir or self .userhome , data_name )
102
108
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 :
109
112
return
110
113
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
114
117
self .writer = self .writers [self .filters .index (self .filter )]
115
118
self ._update_controls ()
119
+ self .save_file ()
116
120
117
121
def save_file (self ):
122
+ if not self .filename :
123
+ self .save_file_as ()
124
+ return
118
125
self .Error .general_error .clear ()
119
126
if not self ._can_save ():
120
127
return
121
- name = self .filename \
122
- + ".gz" * self .writer .SUPPORT_COMPRESSED * self .compress
123
128
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 )
125
131
except IOError as err_value :
126
132
self .Error .general_error (str (err_value ))
127
133
134
+ def _fullname (self ):
135
+ return self .filename \
136
+ + ".gz" * self .writer .SUPPORT_COMPRESSED * self .compress
137
+
128
138
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 )
132
139
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 )
142
145
143
146
self .Error .unsupported_sparse (
144
147
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 ))
148
164
149
165
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
+ )
153
172
154
173
def send_report (self ):
155
174
self .report_data_brief (self .data )
0 commit comments