1- from AnyQt .QtWidgets import QComboBox , QTextEdit , QMessageBox , QApplication
1+ from AnyQt .QtWidgets import QComboBox , QTextEdit , QMessageBox , QApplication , \
2+ QGridLayout , QLineEdit
23from AnyQt .QtGui import QCursor
34from AnyQt .QtCore import Qt
45
6+ from orangewidget .utils .combobox import ComboBoxSearch
7+
58from Orange .data import Table
69from Orange .data .sql .backend import Backend
710from Orange .data .sql .backend .base import BackendError
1417from Orange .widgets .widget import Output , Msg
1518
1619MAX_DL_LIMIT = 1000000
20+ MAX_TABLES = 1000
1721
1822
1923def is_postgres (backend ):
@@ -52,21 +56,19 @@ class Outputs:
5256
5357 buttons_area_orientation = None
5458
59+ TABLE , CUSTOM_SQL = range (2 )
5560 selected_backend = Setting (None )
61+ data_source = Setting (TABLE )
5662 table = Setting (None )
5763 sql = Setting ("" )
5864 guess_values = Setting (True )
59- download = Setting (False )
6065
6166 materialize = Setting (False )
6267 materialize_table_name = Setting ("" )
6368
6469 class Information (OWBaseSql .Information ):
6570 data_sampled = Msg ("Data description was generated from a sample." )
6671
67- class Warning (OWBaseSql .Warning ):
68- missing_extension = Msg ("Database is missing extensions: {}" )
69-
7072 class Error (OWBaseSql .Error ):
7173 no_backends = Msg ("Please install a backend to use this widget." )
7274
@@ -76,9 +78,9 @@ def __init__(self):
7678 self .backendcombo = None
7779 self .tables = None
7880 self .tablecombo = None
81+ self .tabletext = None
7982 self .sqltext = None
8083 self .custom_sql = None
81- self .downloadcb = None
8284 super ().__init__ ()
8385
8486 def _setup_gui (self ):
@@ -106,21 +108,33 @@ def __backend_changed(self):
106108 self .selected_backend = backend .display_name if backend else None
107109
108110 def _add_tables_controls (self ):
109- vbox = gui .vBox (self .controlArea , "Tables" )
110- box = gui .vBox (vbox )
111+ box = gui .vBox (self .controlArea , 'Data Selection' )
112+ form = QGridLayout ()
113+ radio_buttons = gui .radioButtons (
114+ box , self , 'data_source' , orientation = form ,
115+ callback = self .__on_data_source_changed )
116+ radio_table = gui .appendRadioButton (
117+ radio_buttons , 'Table:' , addToLayout = False )
118+ radio_custom_sql = gui .appendRadioButton (
119+ radio_buttons , 'Custom SQL:' , addToLayout = False )
120+
111121 self .tables = TableModel ()
112122
113- self .tablecombo = QComboBox (
123+ self .tablecombo = ComboBoxSearch (
114124 minimumContentsLength = 35 ,
115125 sizeAdjustPolicy = QComboBox .AdjustToMinimumContentsLengthWithIcon
116126 )
117127 self .tablecombo .setModel (self .tables )
118128 self .tablecombo .setToolTip ('table' )
119129 self .tablecombo .activated [int ].connect (self .select_table )
120- box .layout ().addWidget (self .tablecombo )
130+
131+ self .tabletext = QLineEdit (placeholderText = 'TABLE_NAME' )
132+ self .tabletext .setToolTip ('table' )
133+ self .tabletext .editingFinished .connect (self .select_table )
134+ self .tabletext .setVisible (False )
121135
122136 self .custom_sql = gui .vBox (box )
123- self .custom_sql .setVisible (False )
137+ self .custom_sql .setVisible (self . data_source == self . CUSTOM_SQL )
124138 self .sqltext = QTextEdit (self .custom_sql )
125139 self .sqltext .setPlainText (self .sql )
126140 self .custom_sql .layout ().addWidget (self .sqltext )
@@ -133,15 +147,18 @@ def _add_tables_controls(self):
133147
134148 gui .button (self .custom_sql , self , 'Execute' , callback = self .open_table )
135149
136- box .layout ().addWidget (self .custom_sql )
150+ form .addWidget (radio_table , 1 , 0 , Qt .AlignLeft )
151+ form .addWidget (self .tablecombo , 1 , 1 )
152+ form .addWidget (self .tabletext , 1 , 1 )
153+ form .addWidget (radio_custom_sql , 2 , 0 , Qt .AlignLeft )
137154
138155 gui .checkBox (box , self , "guess_values" ,
139156 "Auto-discover categorical variables" ,
140157 callback = self .open_table )
141158
142- self . downloadcb = gui . checkBox ( box , self , "download" ,
143- "Download data to local memory" ,
144- callback = self .open_table )
159+ def __on_data_source_changed ( self ):
160+ self . custom_sql . setVisible ( self . data_source == self . CUSTOM_SQL )
161+ self .select_table ( )
145162
146163 def highlight_error (self , text = "" ):
147164 err = ['' , 'QLineEdit {border: 2px solid red;}' ]
@@ -155,14 +172,6 @@ def get_backend(self):
155172 return self .backends [self .backendcombo .currentIndex ()]
156173
157174 def on_connection_success (self ):
158- if getattr (self .backend , 'missing_extension' , False ):
159- self .Warning .missing_extension (
160- ", " .join (self .backend .missing_extension ))
161- self .download = True
162- self .downloadcb .setEnabled (False )
163- if not is_postgres (self .backend ):
164- self .download = True
165- self .downloadcb .setEnabled (False )
166175 super ().on_connection_success ()
167176 self .refresh_tables ()
168177 self .select_table ()
@@ -173,8 +182,6 @@ def on_connection_error(self, err):
173182
174183 def clear (self ):
175184 super ().clear ()
176- self .Warning .missing_extension .clear ()
177- self .downloadcb .setEnabled (True )
178185 self .highlight_error ()
179186 self .tablecombo .clear ()
180187 self .tablecombo .repaint ()
@@ -186,37 +193,44 @@ def refresh_tables(self):
186193 return
187194
188195 self .tables .append ("Select a table" )
189- self .tables .append ("Custom SQL" )
190- self .tables .extend (self .backend .list_tables (self .schema ))
191- index = self .tablecombo .findText (str (self .table ))
192- self .tablecombo .setCurrentIndex (index if index != - 1 else 0 )
196+ if self .backend .n_tables (self .schema ) <= MAX_TABLES :
197+ self .tables .extend (self .backend .list_tables (self .schema ))
198+ index = self .tablecombo .findText (str (self .table ))
199+ self .tablecombo .setCurrentIndex (index if index != - 1 else 0 )
200+ self .tablecombo .setVisible (True )
201+ self .tabletext .setVisible (False )
202+ else :
203+ self .tablecombo .setVisible (False )
204+ self .tabletext .setVisible (True )
193205 self .tablecombo .repaint ()
194206
195207 # Called on tablecombo selection change:
196208 def select_table (self ):
197- curIdx = self .tablecombo .currentIndex ()
198- if self .tablecombo .itemText (curIdx ) != "Custom SQL" :
199- self .custom_sql .setVisible (False )
209+ if self .data_source == self .TABLE :
200210 return self .open_table ()
201211 else :
202- self .custom_sql .setVisible (True )
203212 self .data_desc_table = None
204- self .database_desc ["Table" ] = "(None)"
213+ if self .database_desc :
214+ self .database_desc ["Table" ] = "(None)"
205215 self .table = None
206216 if len (str (self .sql )) > 14 :
207217 return self .open_table ()
208218 return None
209219
210220 def get_table (self ):
221+ if self .backend is None :
222+ return None
211223 curIdx = self .tablecombo .currentIndex ()
212- if curIdx <= 0 :
224+ if self .data_source == self .TABLE and curIdx <= 0 and \
225+ self .tabletext .text () == "" :
213226 if self .database_desc :
214227 self .database_desc ["Table" ] = "(None)"
215228 self .data_desc_table = None
216229 return None
217230
218- if self .tablecombo .itemText (curIdx ) != "Custom SQL" :
219- self .table = self .tables [self .tablecombo .currentIndex ()]
231+ if self .data_source == self .TABLE :
232+ self .table = self .tables [curIdx ] if curIdx > 0 else \
233+ self .tabletext .text ()
220234 self .database_desc ["Table" ] = self .table
221235 if "Query" in self .database_desc :
222236 del self .database_desc ["Query" ]
@@ -290,45 +304,45 @@ def get_table(self):
290304 QApplication .restoreOverrideCursor ()
291305 table .domain = domain
292306
293- if self .download :
294- if table .approx_len () > AUTO_DL_LIMIT :
295- if is_postgres (self .backend ):
296- confirm = QMessageBox (self )
297- confirm .setIcon (QMessageBox .Warning )
298- confirm .setText ("Data appears to be big. Do you really "
299- "want to download it to local memory?\n "
300- "Table length: {:,}. Limit {:,}" .format (table .approx_len (), MAX_DL_LIMIT ))
301-
302- if table .approx_len () <= MAX_DL_LIMIT :
303- confirm .addButton ("Yes" , QMessageBox .YesRole )
304- no_button = confirm .addButton ("No" , QMessageBox .NoRole )
305- sample_button = confirm .addButton ("Yes, a sample" ,
306- QMessageBox .YesRole )
307- confirm .exec ()
308- if confirm .clickedButton () == no_button :
309- return None
310- elif confirm .clickedButton () == sample_button :
311- table = table .sample_percentage (
312- AUTO_DL_LIMIT / table .approx_len () * 100 )
307+ if table .approx_len () > AUTO_DL_LIMIT :
308+ if is_postgres (self .backend ):
309+ confirm = QMessageBox (self )
310+ confirm .setIcon (QMessageBox .Warning )
311+ confirm .setText ("Data appears to be big. Do you really "
312+ "want to download it to local memory?\n "
313+ "Table length: {:,}. Limit {:,}" .format (
314+ table .approx_len (), MAX_DL_LIMIT ))
315+
316+ if table .approx_len () <= MAX_DL_LIMIT :
317+ confirm .addButton ("Yes" , QMessageBox .YesRole )
318+ no_button = confirm .addButton ("No" , QMessageBox .NoRole )
319+ sample_button = confirm .addButton ("Yes, a sample" ,
320+ QMessageBox .YesRole )
321+ confirm .exec ()
322+ if confirm .clickedButton () == no_button :
323+ return None
324+ elif confirm .clickedButton () == sample_button :
325+ table = table .sample_percentage (
326+ AUTO_DL_LIMIT / table .approx_len () * 100 )
327+ else :
328+ if table .approx_len () > MAX_DL_LIMIT :
329+ QMessageBox .warning (
330+ self , 'Warning' ,
331+ "Data is too big to download.\n "
332+ "Table length: {:,}. Limit {:,}" .format (table .approx_len (), MAX_DL_LIMIT )
333+ )
334+ return None
313335 else :
314- if table . approx_len () > MAX_DL_LIMIT :
315- QMessageBox . warning (
316- self , 'Warning' ,
317- "Data is too big to download. \n "
318- "Table length: {:,}. Limit {:,}" . format ( table . approx_len (), MAX_DL_LIMIT )
319- )
336+ confirm = QMessageBox . question (
337+ self , 'Question' ,
338+ "Data appears to be big. Do you really "
339+ "want to download it to local memory?" ,
340+ QMessageBox . Yes | QMessageBox . No , QMessageBox . No )
341+ if confirm == QMessageBox . No :
320342 return None
321- else :
322- confirm = QMessageBox .question (
323- self , 'Question' ,
324- "Data appears to be big. Do you really "
325- "want to download it to local memory?" ,
326- QMessageBox .Yes | QMessageBox .No , QMessageBox .No )
327- if confirm == QMessageBox .No :
328- return None
329-
330- table .download_data (MAX_DL_LIMIT )
331- table = Table (table )
343+
344+ table .download_data (MAX_DL_LIMIT )
345+ table = Table (table )
332346
333347 return table
334348
0 commit comments