23
23
from functools import partial as ft_partial
26
31
from spyderlib.baseconfig import _
27
32
from spyderlib.utils import programs
28
33
from spyderlib.utils.qthelpers import get_icon, add_actions, create_action
29
34
from spyderlib.py3compat import (TEXT_TYPES, INT_TYPES, to_text_string, u,
32
37
def try_to_parse(value):
33
38
_types = ('int', 'float')
71
76
def datestr_to_datetime(value, dayfirst=True):
72
77
return dateparse(value, dayfirst=dayfirst)
74
#----Background colors for supported types
79
#----Background colors for supported types
77
82
tuple([float] + list(INT_TYPES)): Qt.blue,
96
101
"""Import wizard contents widget"""
97
102
def __init__(self, parent, text):
98
103
QWidget.__init__(self, parent)
100
105
self.text_editor = QTextEdit(self)
101
106
self.text_editor.setText(text)
102
107
self.text_editor.setReadOnly(True)
105
110
type_layout = QHBoxLayout()
106
111
type_label = QLabel(_("Import as"))
111
116
type_layout.addWidget(data_btn)
112
117
code_btn = QRadioButton(_("code"))
113
118
self._as_code = False
114
type_layout.addWidget(code_btn)
119
type_layout.addWidget(code_btn)
115
120
txt_btn = QRadioButton(_("text"))
116
121
type_layout.addWidget(txt_btn)
117
123
h_spacer = QSpacerItem(40, 20,
118
124
QSizePolicy.Expanding, QSizePolicy.Minimum)
119
type_layout.addItem(h_spacer)
125
type_layout.addItem(h_spacer)
120
126
type_frame = QFrame()
121
127
type_frame.setLayout(type_layout)
124
130
grid_layout = QGridLayout()
125
131
grid_layout.setSpacing(0)
127
133
col_label = QLabel(_("Column separator:"))
128
134
grid_layout.addWidget(col_label, 0, 0)
129
135
col_w = QWidget()
130
136
col_btn_layout = QHBoxLayout()
131
137
self.tab_btn = QRadioButton(_("Tab"))
132
self.tab_btn.setChecked(True)
138
self.tab_btn.setChecked(False)
133
139
col_btn_layout.addWidget(self.tab_btn)
134
140
other_btn_col = QRadioButton(_("other"))
141
other_btn_col.setChecked(True)
135
142
col_btn_layout.addWidget(other_btn_col)
136
143
col_w.setLayout(col_btn_layout)
137
144
grid_layout.addWidget(col_w, 0, 1)
138
145
self.line_edt = QLineEdit(",")
139
146
self.line_edt.setMaximumWidth(30)
140
self.line_edt.setEnabled(False)
147
self.line_edt.setEnabled(True)
141
148
self.connect(other_btn_col, SIGNAL("toggled(bool)"),
142
149
self.line_edt, SLOT("setEnabled(bool)"))
143
150
grid_layout.addWidget(self.line_edt, 0, 2)
161
168
grid_layout.addWidget(self.line_edt_row, 1, 2)
163
170
grid_layout.setRowMinimumHeight(2, 15)
165
other_group = QGroupBox(_("Additionnal options"))
172
other_group = QGroupBox(_("Additional options"))
166
173
other_layout = QGridLayout()
167
174
other_group.setLayout(other_layout)
174
181
self.skiprows_edt)
175
182
self.skiprows_edt.setValidator(intvalid)
176
183
other_layout.addWidget(self.skiprows_edt, 0, 1)
178
185
other_layout.setColumnMinimumWidth(2, 5)
180
187
comments_label = QLabel(_("Comments:"))
181
188
other_layout.addWidget(comments_label, 0, 3)
182
189
self.comments_edt = QLineEdit('#')
183
190
self.comments_edt.setMaximumWidth(30)
184
191
other_layout.addWidget(self.comments_edt, 0, 4)
186
193
self.trnsp_box = QCheckBox(_("Transpose"))
187
194
#self.trnsp_box.setEnabled(False)
188
195
other_layout.addWidget(self.trnsp_box, 1, 0, 2, 0)
190
197
grid_layout.addWidget(other_group, 3, 0, 2, 0)
192
199
opts_frame = QFrame()
193
200
opts_frame.setLayout(grid_layout)
195
202
self.connect(data_btn, SIGNAL("toggled(bool)"),
196
203
opts_frame, SLOT("setEnabled(bool)"))
197
204
self.connect(data_btn, SIGNAL("toggled(bool)"),
225
232
if self.tab_btn.isChecked():
227
234
return to_text_string(self.line_edt.text())
229
236
def get_row_sep(self):
230
237
"""Return the row separator"""
231
238
if self.eol_btn.isChecked():
233
240
return to_text_string(self.line_edt_row.text())
235
242
def get_skiprows(self):
236
243
"""Return number of lines to be skipped"""
237
244
return int(to_text_string(self.skiprows_edt.text()))
239
246
def get_comments(self):
240
247
"""Return comment string"""
241
248
return to_text_string(self.comments_edt.text())
251
258
"""Set if code type conversion"""
252
259
self._as_code = as_code
254
262
class PreviewTableModel(QAbstractTableModel):
255
263
"""Import wizard preview table model"""
256
264
def __init__(self, data=[], parent=None):
260
268
def rowCount(self, parent=QModelIndex()):
261
269
"""Return row count"""
262
270
return len(self._data)
264
272
def columnCount(self, parent=QModelIndex()):
265
273
"""Return column count"""
266
274
return len(self._data[0])
268
276
def _display_data(self, index):
269
277
"""Return a data element"""
270
278
return to_qvariant(self._data[index.row()][index.column()])
272
280
def data(self, index, role=Qt.DisplayRole):
273
281
"""Return a model data element"""
274
282
if not index.isValid():
276
284
if role == Qt.DisplayRole:
277
285
return self._display_data(index)
278
286
elif role == Qt.BackgroundColorRole:
279
return to_qvariant(get_color(self._data[index.row()][index.column()], .2))
287
return to_qvariant(get_color(self._data[index.row()][index.column()], .2))
280
288
elif role == Qt.TextAlignmentRole:
281
289
return to_qvariant(int(Qt.AlignRight|Qt.AlignVCenter))
282
290
return to_qvariant()
284
292
def setData(self, index, value, role=Qt.EditRole):
285
293
"""Set model data"""
312
320
self._data[index.row()][index.column()])
313
321
elif kwargs['atype'] == "float":
314
322
self._data[index.row()][index.column()] = float(
315
self._data[index.row()][index.column()])
323
self._data[index.row()][index.column()])
316
324
self.emit(SIGNAL("dataChanged(QModelIndex,QModelIndex)"), index, index)
317
325
except Exception as instance:
338
346
triggered=ft_partial(self.parse_to_type, atype="int"))
339
347
self.float_action = create_action(self, "float",
340
348
triggered=ft_partial(self.parse_to_type, atype="float"))
342
350
# Setting up menus
343
351
self.date_menu = QMenu()
344
352
self.date_menu.setTitle("Date")
398
406
if not indexes: return
399
407
for index in indexes:
400
408
self.model().parse_data_type(index, **kwargs)
402
410
def contextMenuEvent(self, event):
403
411
"""Reimplement Qt method"""
404
412
self.opt_menu.popup(event.globalPos())
407
415
class PreviewWidget(QWidget):
408
416
"""Import wizard preview widget"""
410
418
def __init__(self, parent):
411
419
QWidget.__init__(self, parent)
413
421
vert_layout = QVBoxLayout()
416
424
type_layout = QHBoxLayout()
417
425
type_label = QLabel(_("Import as"))
418
426
type_layout.addWidget(type_label)
419
428
self.array_btn = array_btn = QRadioButton(_("array"))
420
429
array_btn.setEnabled(ndarray is not FakeObject)
421
430
array_btn.setChecked(ndarray is not FakeObject)
423
431
type_layout.addWidget(array_btn)
424
433
list_btn = QRadioButton(_("list"))
425
434
list_btn.setChecked(not array_btn.isChecked())
426
type_layout.addWidget(list_btn)
435
type_layout.addWidget(list_btn)
438
self.df_btn = df_btn = QRadioButton(_("DataFrame"))
439
df_btn.setChecked(False)
440
type_layout.addWidget(df_btn)
427
442
h_spacer = QSpacerItem(40, 20,
428
443
QSizePolicy.Expanding, QSizePolicy.Minimum)
429
type_layout.addItem(h_spacer)
444
type_layout.addItem(h_spacer)
430
445
type_frame = QFrame()
431
446
type_frame.setLayout(type_layout)
433
448
self._table_view = PreviewTable(self)
434
449
vert_layout.addWidget(type_frame)
435
450
vert_layout.addWidget(self._table_view)
438
453
def open_data(self, text, colsep=u("\t"), rowsep=u("\n"),
439
454
transpose=False, skiprows=0, comments='#'):
440
455
"""Open clipboard text as table"""
458
self.pd_info = dict(sep=colsep, lineterminator=rowsep,
459
skiprows=skiprows,comment=comments)
441
460
self._table_view.process_data(text, colsep, rowsep, transpose,
442
461
skiprows, comments)
444
463
def get_data(self):
445
464
"""Return table data"""
446
465
return self._table_view.get_data()
450
469
def __init__(self, parent, text,
451
470
title=None, icon=None, contents_title=None, varname=None):
452
471
QDialog.__init__(self, parent)
454
473
# Destroying the C++ object right after closing the dialog box,
455
474
# otherwise it may be garbage-collected in another QThread
456
475
# (e.g. the editor's analysis thread in Spyder), thus leading to
457
476
# a segmentation fault on UNIX or an application crash on Windows
458
477
self.setAttribute(Qt.WA_DeleteOnClose)
460
479
if title is None:
461
480
title = _("Import wizard")
462
481
self.setWindowTitle(title)
464
483
self.setWindowIcon(get_icon("fileimport.png"))
465
484
if contents_title is None:
466
485
contents_title = _("Raw text")
468
487
if varname is None:
469
488
varname = _("variable_name")
471
490
self.var_name, self.clip_data = None, None
474
493
self.tab_widget = QTabWidget(self)
475
494
self.text_widget = ContentsWidget(self, text)
476
495
self.table_widget = PreviewWidget(self)
478
497
self.tab_widget.addTab(self.text_widget, _("text"))
479
498
self.tab_widget.setTabText(0, contents_title)
480
499
self.tab_widget.addTab(self.table_widget, _("table"))
481
500
self.tab_widget.setTabText(1, _("Preview"))
482
501
self.tab_widget.setTabEnabled(1, False)
484
503
name_layout = QHBoxLayout()
485
504
name_label = QLabel(_("Variable Name"))
486
505
name_layout.addWidget(name_label)
488
507
self.name_edt = QLineEdit()
489
508
self.name_edt.setText(varname)
490
509
name_layout.addWidget(self.name_edt)
492
511
btns_layout = QHBoxLayout()
493
512
cancel_btn = QPushButton(_("Cancel"))
494
513
btns_layout.addWidget(cancel_btn)
510
529
btns_layout.addWidget(self.done_btn)
511
530
self.connect(self.done_btn, SIGNAL("clicked()"),
512
531
self, SLOT("process()"))
514
533
self.connect(self.text_widget, SIGNAL("asDataChanged(bool)"),
515
534
self.fwd_btn, SLOT("setEnabled(bool)"))
516
535
self.connect(self.text_widget, SIGNAL("asDataChanged(bool)"),
527
546
self.tab_widget.setTabEnabled(i, False)
528
547
self.tab_widget.setTabEnabled(tab_idx, True)
529
548
self.tab_widget.setCurrentIndex(tab_idx)
531
550
def _set_step(self, step):
532
551
"""Proceed to a given step"""
533
552
new_tab = self.tab_widget.currentIndex() + step
578
597
self.table_widget.get_data())
579
598
if self.table_widget.array_btn.isChecked():
580
599
return array(data)
600
elif pd and self.table_widget.df_btn.isChecked():
601
info = self.table_widget.pd_info
602
buf = io.StringIO(self.table_widget.pd_text)
603
return pd.read_csv(buf, **info)
583
606
def _get_plain_text(self):