~ubuntu-branches/ubuntu/trusty/spyder/trusty-proposed

« back to all changes in this revision

Viewing changes to spyderlib/plugins/workspace.py

  • Committer: Bazaar Package Importer
  • Author(s): Ludovic Aubry
  • Date: 2010-06-28 23:43:02 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20100628234302-3xnz0gcu0w83282r
Tags: 1.1.1-1
* New upstream release
* New maintainer address (Closes: #586833)
* Build with python 2.6 (Closes: #586824)

Show diffs side-by-side

added added

removed removed

Lines of Context:
4
4
# Licensed under the terms of the MIT License
5
5
# (see spyderlib/__init__.py for details)
6
6
 
7
 
"""Workspace widget"""
 
7
"""Workspace Plugin"""
8
8
 
9
9
# pylint: disable-msg=C0103
10
10
# pylint: disable-msg=R0903
11
11
# pylint: disable-msg=R0911
12
12
# pylint: disable-msg=R0201
13
13
 
14
 
from PyQt4.QtGui import QFileDialog, QMessageBox, QFontDialog, QMenu
 
14
from PyQt4.QtGui import QMessageBox, QFontDialog, QMenu
15
15
from PyQt4.QtCore import SIGNAL
16
16
 
17
17
import os, sys
23
23
# Local imports
24
24
from spyderlib.config import (CONF, get_conf_path, str2type, get_icon,
25
25
                              get_font, set_font)
26
 
from spyderlib.utils.qthelpers import create_action, add_actions, translate
27
 
from spyderlib.utils.iofuncs import (save_dictionary, load_dictionary,
28
 
                                     load_array, load_image, load_dicom,
29
 
                                     load_matlab, save_matlab)
 
26
from spyderlib.utils import fix_reference_name
 
27
from spyderlib.utils.qthelpers import create_action, add_actions
 
28
from spyderlib.utils.iofuncs import iofunctions
30
29
from spyderlib.widgets.dicteditor import DictEditorTableView, globalsfilter
31
 
from spyderlib.plugins import PluginMixin
 
30
from spyderlib.plugins import SpyderPluginMixin
32
31
 
33
32
 
34
33
FILTERS = tuple(str2type(CONF.get('workspace', 'filters')))
47
46
                         excluded_names=excluded_names)
48
47
 
49
48
 
50
 
class Workspace(DictEditorTableView, PluginMixin):
 
49
class Workspace(DictEditorTableView, SpyderPluginMixin):
51
50
    """
52
51
    Workspace widget (namespace explorer)
53
52
    """
65
64
        DictEditorTableView.__init__(self, parent, None, names=True,
66
65
                                     truncate=truncate, inplace=inplace,
67
66
                                     minmax=minmax, collvalue=collvalue)
68
 
        PluginMixin.__init__(self, parent)
 
67
        SpyderPluginMixin.__init__(self, parent)
69
68
        
70
 
        self.setup_io()
71
69
        self.load_temp_namespace()
72
70
        
73
71
        self.setFont(get_font(self.ID))
74
72
 
75
 
    def setup_io(self):
76
 
        """Setup I/O functions and filters"""
77
 
        iofuncs = (
78
 
                   ('.spydata', translate('Workspace', "Spyder data files"),
79
 
                                load_dictionary, save_dictionary),
80
 
                   ('.npy',     translate('Workspace', "NumPy arrays"),
81
 
                                load_array, None),
82
 
                   ('.mat',     translate('Workspace', "Matlab files"),
83
 
                                load_matlab, save_matlab),
84
 
                   ('.csv',     translate('Workspace', "CSV text files"),
85
 
                                'import_wizard', None),
86
 
                   ('.txt',     translate('Workspace', "Text files"),
87
 
                                'import_wizard', None),
88
 
                   ('.jpg',     translate('Workspace', "JPEG images"),
89
 
                                load_image, None),
90
 
                   ('.png',     translate('Workspace', "PNG images"),
91
 
                                load_image, None),
92
 
                   ('.gif',     translate('Workspace', "GIF images"),
93
 
                                load_image, None),
94
 
                   ('.tif',     translate('Workspace', "TIFF images"),
95
 
                                load_image, None),
96
 
                   ('.dcm',     translate('Workspace', "DICOM images"),
97
 
                                load_dicom, None),
98
 
                   )
99
 
        load_funcs = {}
100
 
        save_funcs = {}
101
 
        load_filters = []
102
 
        save_filters = []
103
 
        load_ext = []
104
 
        for ext, name, loadfunc, savefunc in iofuncs:
105
 
            filter_str = unicode(name + " (*%s)" % ext)
106
 
            if loadfunc is not None:
107
 
                load_filters.append(filter_str)
108
 
                load_funcs[ext] = loadfunc
109
 
                load_ext.append(ext)
110
 
            if savefunc is not None:
111
 
                save_filters.append(filter_str)
112
 
                save_funcs[ext] = savefunc
113
 
        load_filters.insert(0, unicode(self.tr("Supported files")+" (*"+\
114
 
                                       " *".join(load_ext)+")"))
115
 
        self.load_filters = "\n".join(load_filters)
116
 
        self.save_filters = "\n".join(save_filters)
117
 
        self.load_funcs = load_funcs
118
 
        self.save_funcs = save_funcs
119
 
        
120
 
    def get_widget_title(self):
 
73
    #------ SpyderPluginWidget API ---------------------------------------------    
 
74
    def get_plugin_title(self):
121
75
        """Return widget title"""
122
76
        return self.tr('Workspace')
123
77
    
128
82
        """
129
83
        return self
130
84
        
131
 
    def set_interpreter(self, interpreter):
132
 
        """Bind to interpreter"""
133
 
        self.interpreter = interpreter
134
 
        self.refresh(force=True)
135
 
        
136
 
    def get_namespace(self, itermax=ITERMAX):
137
 
        """Return filtered namespace"""
138
 
        return wsfilter(self.namespace, itermax=itermax)
139
 
    
140
 
    def __clear_namespace(self):
141
 
        """Clear namespace"""
142
 
        keys = self.get_namespace().keys()
143
 
        for key in keys:
144
 
            self.namespace.pop(key)
145
 
        self.refresh(force=True)
146
 
    
147
 
    def clear(self):
148
 
        """Ask to clear workspace"""
149
 
        answer = QMessageBox.question(self, self.tr("Clear workspace"),
150
 
                    self.tr("Do you want to clear all data from workspace?"),
151
 
                    QMessageBox.Yes | QMessageBox.No)
152
 
        if answer == QMessageBox.Yes:
153
 
            self.__clear_namespace()
154
 
 
155
 
    def refresh(self, force=False):
156
 
        """Refresh widget"""
157
 
        if CONF.get(self.ID, 'autorefresh') or force:
158
 
            self.refresh_editor()
159
 
        
160
 
    def refresh_editor(self):
161
 
        """Refresh DictEditor"""
162
 
        if self.interpreter is not None:
163
 
            self.namespace = self.interpreter.namespace
164
 
        self.set_filter( wsfilter )
165
 
        self.set_data( self.namespace )
166
 
        self.adjust_columns()
167
 
        
168
 
    def set_actions(self):
 
85
    def get_plugin_actions(self):
169
86
        """Setup actions"""
170
87
        import_action = create_action(self, self.tr("Import data..."), None,
171
88
            'ws_open.png', self.tr("Import data to workspace"),
232
149
                        option_menu)
233
150
        toolbar_actions = (refresh_action, import_action, save_as_action)
234
151
        return (menu_actions, toolbar_actions)
235
 
        
236
 
    def change_font1(self):
237
 
        """Change font"""
238
 
        self.__change_font('dicteditor_header')
239
 
        
240
 
    def change_font2(self):
241
 
        """Change font"""
242
 
        self.__change_font('dicteditor')
243
 
    
244
 
    def __change_font(self, section):
245
 
        font, valid = QFontDialog.getFont(get_font(section), self,
246
 
                                          self.tr("Select a new font"))
247
 
        if valid:
248
 
            set_font(font, section)
249
 
    
250
 
    def toggle_autorefresh(self, checked):
251
 
        """Toggle autorefresh mode"""
252
 
        CONF.set(self.ID, 'autorefresh', checked)
253
 
        self.refresh()
254
 
        
255
 
    def toggle_autosave(self, checked):
256
 
        """Toggle autosave mode"""
257
 
        CONF.set(self.ID, 'autosave', checked)
258
 
        
259
 
    def closing(self, cancelable=False):
 
152
 
 
153
    def refresh_plugin(self, force=False):
 
154
        """Refresh widget"""
 
155
        if CONF.get(self.ID, 'autorefresh') or force:
 
156
            self.refresh_editor()
 
157
        
 
158
    def closing_plugin(self, cancelable=False):
260
159
        """Perform actions before parent main window is closed"""
261
160
        if CONF.get(self.ID, 'autosave'):
262
161
            # Saving workspace
278
177
                buttons = QMessageBox.Yes | QMessageBox.No
279
178
                if cancelable:
280
179
                    buttons = buttons | QMessageBox.Cancel
281
 
                answer = QMessageBox.question(self, self.get_widget_title(),
 
180
                answer = QMessageBox.question(self, self.get_plugin_title(),
282
181
                   self.tr("Workspace is currently keeping reference "
283
182
                           "to %1 object%2.\n\nDo you want to save %3?") \
284
183
                   .arg(srefnb).arg(s_or_not).arg(it_or_them), buttons)
291
190
                    # Removing last saved workspace
292
191
                    os.remove(self.TEMPFILE_PATH)
293
192
        return True
 
193
        
 
194
    #------ Public API ---------------------------------------------------------
 
195
    def set_interpreter(self, interpreter):
 
196
        """Bind to interpreter"""
 
197
        self.interpreter = interpreter
 
198
        self.refresh_plugin(force=True)
 
199
        
 
200
    def get_namespace(self, itermax=ITERMAX):
 
201
        """Return filtered namespace"""
 
202
        return wsfilter(self.namespace, itermax=itermax)
 
203
    
 
204
    def __clear_namespace(self):
 
205
        """Clear namespace"""
 
206
        keys = self.get_namespace().keys()
 
207
        for key in keys:
 
208
            self.namespace.pop(key)
 
209
        self.refresh_plugin(force=True)
 
210
    
 
211
    def clear(self):
 
212
        """Ask to clear workspace"""
 
213
        answer = QMessageBox.question(self, self.tr("Clear workspace"),
 
214
                    self.tr("Do you want to clear all data from workspace?"),
 
215
                    QMessageBox.Yes | QMessageBox.No)
 
216
        if answer == QMessageBox.Yes:
 
217
            self.__clear_namespace()
 
218
        
 
219
    def refresh_editor(self):
 
220
        """Refresh DictEditor"""
 
221
        if self.interpreter is not None:
 
222
            self.namespace = self.interpreter.namespace
 
223
        self.set_filter( wsfilter )
 
224
        self.set_data( self.namespace )
 
225
        self.adjust_columns()
 
226
        
 
227
    def change_font1(self):
 
228
        """Change font"""
 
229
        self.__change_font('dicteditor_header')
 
230
        
 
231
    def change_font2(self):
 
232
        """Change font"""
 
233
        self.__change_font('dicteditor')
 
234
    
 
235
    def __change_font(self, section):
 
236
        font, valid = QFontDialog.getFont(get_font(section), self,
 
237
                                          self.tr("Select a new font"))
 
238
        if valid:
 
239
            set_font(font, section)
 
240
    
 
241
    def toggle_autorefresh(self, checked):
 
242
        """Toggle autorefresh mode"""
 
243
        CONF.set(self.ID, 'autorefresh', checked)
 
244
        self.refresh_plugin()
 
245
        
 
246
    def toggle_autosave(self, checked):
 
247
        """Toggle autosave mode"""
 
248
        CONF.set(self.ID, 'autosave', checked)
294
249
    
295
250
    def load_temp_namespace(self):
296
251
        """Attempt to load last session namespace"""
299
254
            self.import_data(self.filename)
300
255
        else:
301
256
            self.namespace = None
302
 
            self.refresh(force=True)
 
257
            self.refresh_plugin(force=True)
303
258
 
304
259
    def import_data(self, filename=None):
305
260
        """
310
265
        if filename is None:
311
266
            self.emit(SIGNAL('redirect_stdio(bool)'), False)
312
267
            basedir = osp.dirname(self.filename)
313
 
            filename = QFileDialog.getOpenFileName(self,
314
 
                          title, basedir, self.load_filters)
 
268
            filename = iofunctions.get_open_filename(self, basedir, title)
315
269
            self.emit(SIGNAL('redirect_stdio(bool)'), True)
316
270
            if filename:
317
271
                filename = unicode(filename)
318
272
            else:
319
273
                return
320
274
        self.filename = unicode(filename)
321
 
        ext = osp.splitext(self.filename)[1]
 
275
        ext = osp.splitext(self.filename)[1].lower()
322
276
        
323
 
        if ext not in self.load_funcs:
 
277
        if ext not in iofunctions.load_funcs:
324
278
            buttons = QMessageBox.Yes | QMessageBox.Cancel
325
279
            answer = QMessageBox.question(self, title,
326
280
                       self.tr("<b>Unsupported file type '%1'</b><br><br>"
331
285
            else:
332
286
                load_func = 'import_wizard'
333
287
        else:
334
 
            load_func = self.load_funcs[ext]
 
288
            load_func = iofunctions.load_funcs[ext]
335
289
            
336
290
        if isinstance(load_func, basestring): # 'import_wizard' (self.setup_io)
337
291
            # Import data with import wizard
345
299
        else:
346
300
            self.starting_long_process(self.tr("Loading data..."))
347
301
            namespace, error_message = load_func(self.filename)
348
 
            self.ending_long_process()           
 
302
            if self.namespace is not None:
 
303
                for key in namespace.keys():
 
304
                    new_key = fix_reference_name(key,
 
305
                                 blacklist=self.interpreter.namespace.keys())
 
306
                    if new_key != key:
 
307
                        namespace[new_key] = namespace.pop(key)
 
308
            self.ending_long_process()
349
309
            if error_message is None:
350
310
                if self.namespace is None:
351
311
                    self.namespace = namespace
357
317
                                 self.tr("<b>Unable to load '%1'</b>"
358
318
                                         "<br><br>Error message:<br>%2") \
359
319
                                         .arg(self.filename).arg(error_message))
360
 
        self.refresh(force=True)
 
320
        self.refresh_plugin(force=True)
361
321
 
362
322
    def save_as(self):
363
323
        """Save current workspace as"""
364
324
        self.emit(SIGNAL('redirect_stdio(bool)'), False)
365
 
        filename = QFileDialog.getSaveFileName(self,
366
 
                      self.tr("Save workspace"), self.filename,
367
 
                      self.save_filters)
 
325
        filename = iofunctions.get_save_filename(self, self.filename,
 
326
                                                  self.tr("Save workspace"))
368
327
        self.emit(SIGNAL('redirect_stdio(bool)'), True)
369
328
        if filename:
370
329
            self.filename = unicode(filename)
376
335
        """Save workspace"""
377
336
        title = self.tr("Save workspace")
378
337
        
379
 
        ext = osp.splitext(filename)[1]
380
 
        if ext not in self.save_funcs:
381
 
            QMessageBox.critical(self, title,
382
 
                                 self.tr("<b>Unsupported file type '%1'</b>") \
383
 
                                         .arg(ext))
384
 
            return
385
 
        
386
338
        self.starting_long_process(self.tr("Saving workspace..."))
387
339
        namespace = self.get_namespace(itermax=-1).copy()
388
 
        error_message = self.save_funcs[ext](namespace, filename)
 
340
        error_message = iofunctions.save(namespace, filename)
389
341
        self.ending_long_process()
390
342
        
391
343
        if error_message is not None:
394
346
                                    "<br><br>Error message:<br>%1") \
395
347
                            .arg(error_message))
396
348
            
397
 
        self.refresh(force=True)
 
349
        self.refresh_plugin(force=True)
398
350
        return True
399
351
 
400
352
    def toggle_exclude_private(self, checked):
401
353
        """Toggle exclude private references"""
402
354
        CONF.set(self.ID, 'exclude_private', checked)
403
 
        self.refresh(force=True)
 
355
        self.refresh_plugin(force=True)
404
356
        
405
357
    def toggle_exclude_upper(self, checked):
406
358
        """Toggle exclude upper-case references"""
407
359
        CONF.set(self.ID, 'exclude_upper', checked)
408
 
        self.refresh(force=True)
 
360
        self.refresh_plugin(force=True)
409
361
 
410
362
    def toggle_exclude_unsupported(self, checked):
411
363
        """Toggle exclude unsupported datatypes"""
412
364
        CONF.set(self.ID, 'exclude_unsupported', checked)
413
 
        self.refresh(force=True)
 
365
        self.refresh_plugin(force=True)
414
366
 
415
367
    #----Focus
416
368
    def focusInEvent(self, event):