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

« back to all changes in this revision

Viewing changes to spyderlib/widgets/dicteditor.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:
26
26
 
27
27
# Local import
28
28
from spyderlib.config import get_icon, get_font
29
 
from spyderlib.utils.qthelpers import translate, add_actions, create_action
 
29
from spyderlib.utils import fix_reference_name
 
30
from spyderlib.utils.qthelpers import (translate, add_actions, create_action,
 
31
                                       qapplication)
30
32
from spyderlib.widgets.texteditor import TextEditor
31
33
from spyderlib.widgets.importwizard import ImportWizard
32
34
 
42
44
        """Fake ndarray"""
43
45
        pass
44
46
 
 
47
#----PIL Images support
 
48
try:
 
49
    from PIL.Image import Image
 
50
except:
 
51
    class Image(FakeObject):
 
52
        """Fake PIL Image"""
 
53
        pass
 
54
 
45
55
#----Misc.
46
56
def address(obj):
47
57
    """Return object address as a string: '<classname @ address>'"""
70
80
          tuple: Qt.lightGray,
71
81
          (str, unicode): Qt.darkRed,
72
82
          ndarray: Qt.green,
 
83
          Image: Qt.darkGreen,
73
84
          datetime.date: Qt.darkYellow,
74
85
          }
75
86
 
104
115
            return 'Min: %r\nMax: %r' % (value.min(), value.max())
105
116
        except TypeError:
106
117
            pass
 
118
    if isinstance(value, Image):
 
119
        return '%s  Mode: %s' % (address(value), value.mode)
107
120
    if not isinstance(value, (str, unicode)):
108
121
        if isinstance(value, (list, tuple, dict, set)) and not collvalue:            
109
122
            value = address(value)
148
161
        return len(item)
149
162
    elif isinstance(item, ndarray):
150
163
        return item.shape
 
164
    elif isinstance(item, Image):
 
165
        return item.size
151
166
    else:
152
167
        return 1
153
168
 
158
173
           if not found else found[0]
159
174
    if isinstance(item, ndarray):
160
175
        text = item.dtype.name
 
176
    if isinstance(item, Image):
 
177
        text = "Image"
161
178
    return text[text.find('.')+1:]
162
179
 
163
180
 
419
436
                    # (ArrayEditor does not make a copy of value)
420
437
                    self.set_value(index, value)
421
438
            return None
 
439
        #---showing image
 
440
        elif isinstance(value, Image) and ndarray is not FakeObject \
 
441
             and Image is not FakeObject:
 
442
            value.show()
 
443
            return None
422
444
        #---editor = QDateTimeEdit
423
445
        elif isinstance(value, datetime.datetime) and not self.inplace:
424
446
            editor = QDateTimeEdit(value, parent)
501
523
    def __init__(self, parent):
502
524
        QTableView.__init__(self, parent)
503
525
        self.array_filename = None
 
526
        self.menu = None
 
527
        self.empty_ws_menu = None
504
528
        
505
529
    def setup_table(self):
506
530
        """Setup table"""
512
536
    
513
537
    def setup_menu(self, truncate, minmax, inplace, collvalue):
514
538
        """Setup context menu"""
 
539
        self.empty_ws_menu = QMenu(self)
 
540
        self.paste_action = create_action(self,
 
541
                                      translate("DictEditor", "Paste"),
 
542
                                      icon=get_icon('editpaste.png'),
 
543
                                      triggered=self.paste)
 
544
        self.empty_ws_menu.addAction(self.paste_action)
 
545
        
 
546
        self.copy_action = create_action(self,
 
547
                                      translate("DictEditor", "Copy"),
 
548
                                      icon=get_icon('editcopy.png'),
 
549
                                      triggered=self.copy)                                      
515
550
        self.edit_action = create_action(self, 
516
551
                                      translate("DictEditor", "Edit"),
517
552
                                      icon=get_icon('edit.png'),
573
608
                                    triggered=self.duplicate_item)
574
609
        menu = QMenu(self)
575
610
        menu_actions = [self.edit_action, self.plot_action, self.imshow_action,
576
 
                        self.save_array_action,
577
 
                        self.insert_action, self.remove_action, None,
578
 
                        self.rename_action,self.duplicate_action, None,
579
 
                        self.truncate_action, self.inplace_action,
 
611
                        self.save_array_action, self.insert_action,
 
612
                        self.remove_action, self.copy_action, self.paste_action,
 
613
                        None, self.rename_action,self.duplicate_action,
 
614
                        None, self.truncate_action, self.inplace_action,
580
615
                        self.collvalue_action]
581
616
        if ndarray is not FakeObject:
582
617
            menu_actions.append(self.minmax_action)
594
629
    def refresh_plot_entries(self, index):
595
630
        if index.isValid():
596
631
            value = self.delegate.get_value(index)
 
632
            is_list = isinstance(value, (tuple, list))
597
633
            is_array = isinstance(value, ndarray) and len(value) != 0
598
 
            condition_plot = is_array and len(value.shape) <= 2
599
 
            condition_imshow = condition_plot and min(value.shape) > 2
 
634
            condition_plot = (is_array and len(value.shape) <= 2)
 
635
            condition_imshow = condition_plot and value.ndim == 2
600
636
        else:
601
637
            is_array = condition_plot = condition_imshow = False
602
 
        self.plot_action.setVisible(condition_plot)
 
638
        self.plot_action.setVisible(condition_plot or is_list)
603
639
        self.imshow_action.setVisible(condition_imshow)
604
640
        self.save_array_action.setVisible(is_array)
605
641
        
638
674
        elif event.key() == Qt.Key_F2:
639
675
            self.rename_item()
640
676
            event.accept()
 
677
        elif event == QKeySequence.Copy:
 
678
            self.copy()
 
679
            event.accept()
641
680
        elif event == QKeySequence.Paste:
642
681
            self.paste()
643
682
            event.accept()
689
728
        for index in indexes:
690
729
            if not index.isValid():
691
730
                return
 
731
        one = translate("DictEditor", "Do you want to remove selected item?")
 
732
        more = translate("DictEditor",
 
733
                         "Do you want to remove all selected items?")
692
734
        answer = QMessageBox.question(self,
693
 
            translate("DictEditor", "Remove"),
694
 
            translate("DictEditor", "Do you want to remove selected item%1?") \
695
 
            .arg('s' if len(indexes)>1 else ''),
696
 
            QMessageBox.Yes | QMessageBox.No)
 
735
                                      translate("DictEditor", "Remove"),
 
736
                                      one if len(indexes) == 1 else more,
 
737
                                      QMessageBox.Yes | QMessageBox.No)
697
738
        if answer == QMessageBox.Yes:
698
739
            idx_rows = unsorted_unique(map(lambda idx: idx.row(), indexes))
699
740
            keys = [ self.model.keys[idx_row] for idx_row in idx_rows ]
759
800
            
760
801
    def __prepare_plot(self):
761
802
        try:
762
 
            from matplotlib import rcParams
763
 
            rcParams['backend'] = 'Qt4agg'
 
803
            from spyderlib import mpl_patch
 
804
            mpl_patch.configure(backend="Qt4Agg")
 
805
            mpl_patch.apply()
764
806
            return True
765
807
        except ImportError:
766
808
            QMessageBox.warning(self, translate("DictEditor", "Import error"),
771
813
        """Plot item"""
772
814
        index = self.currentIndex()
773
815
        if self.__prepare_plot():
774
 
            from pylab import plot, show
 
816
            try:
 
817
                import guiqwt.pyplot as plt
 
818
            except ImportError:
 
819
                import matplotlib.pyplot as plt
775
820
            data = self.delegate.get_value(index)
776
 
            plot(data)
777
 
            show()
 
821
            try:
 
822
                plt.figure()
 
823
                plt.plot(data)
 
824
                plt.show()
 
825
            except ValueError, error:
 
826
                QMessageBox.critical(self, translate("DictEditor", "Plot"),
 
827
                    translate("DictEditor", "<b>Unable to plot data.</b>"
 
828
                              "<br><br>Error message:<br>%1").arg(str(error)))
778
829
            
779
830
    def imshow_item(self):
780
831
        """Imshow item"""
781
832
        index = self.currentIndex()
782
833
        if self.__prepare_plot():
783
 
            from pylab import imshow, show
 
834
            try:
 
835
                import guiqwt.pyplot as plt
 
836
            except ImportError:
 
837
                import matplotlib.pyplot as plt
784
838
            data = self.delegate.get_value(index)
785
 
            imshow(data)
786
 
            show()
 
839
            try:
 
840
                plt.figure()
 
841
                plt.imshow(data)
 
842
                plt.show()
 
843
            except ValueError, error:
 
844
                QMessageBox.critical(self, translate("DictEditor", "Plot"),
 
845
                    translate("DictEditor", "<b>Unable to show image.</b>"
 
846
                              "<br><br>Error message:<br>%1").arg(str(error)))
787
847
            
788
848
    def save_array(self):
789
849
        """Save array"""
804
864
                QMessageBox.critical(self, title,
805
865
                     translate('DictEditor', "<b>Unable to save array</b>"
806
866
                               "<br><br>Error message:<br>%1").arg(str(error)))
807
 
        
808
 
 
809
 
class DictEditorTableView(BaseTableView):
810
 
    """DictEditor table view"""
811
 
    def __init__(self, parent, data, readonly=False, title="",
812
 
                 names=False, truncate=True, minmax=False,
813
 
                 inplace=False, collvalue=True):
814
 
        BaseTableView.__init__(self, parent)
815
 
        self.dictfilter = None
816
 
        self.readonly = readonly or isinstance(data, tuple)
817
 
        self.model = None
818
 
        self.delegate = None
819
 
        DictModelClass = ReadOnlyDictModel if self.readonly else DictModel
820
 
        self.model = DictModelClass(self, data, title, names=names,
821
 
                                    truncate=truncate, minmax=minmax,
822
 
                                    collvalue=collvalue)
823
 
        self.setModel(self.model)
824
 
        self.delegate = DictDelegate(self, inplace=inplace)
825
 
        self.setItemDelegate(self.delegate)
826
 
 
827
 
        self.setup_table()
828
 
        self.menu = self.setup_menu(truncate, minmax, inplace, collvalue)
829
 
        self.copy_action = create_action(self,
830
 
                                      translate("DictEditor", "Copy"),
831
 
                                      icon=get_icon('editcopy.png'),
832
 
                                      triggered=self.copy)                                      
833
 
        self.paste_action = create_action(self,
834
 
                                      translate("DictEditor", "Paste"),
835
 
                                      icon=get_icon('editpaste.png'),
836
 
                                      triggered=self.paste)
837
 
        self.menu.insertAction(self.remove_action, self.copy_action)
838
 
        self.menu.insertAction(self.remove_action, self.paste_action)
839
 
        
840
 
        self.empty_ws_menu = QMenu(self)
841
 
        self.empty_ws_menu.addAction(self.paste_action)
842
 
    
843
 
    def remove_values(self, keys):
844
 
        """
845
 
        Remove values from data
846
 
        (implemented differently for remote table view)
847
 
        """
848
 
        data = self.model.get_data()
849
 
        for key in sorted(keys,reverse=True):
850
 
            data.pop(key)
851
 
            self.set_data(data)
852
 
 
853
 
    def copy_value(self, orig_key, new_key):
854
 
        """
855
 
        Copy value
856
 
        (implemented differently for remote table view)
857
 
        """
858
 
        data = self.model.get_data()
859
 
        data[new_key] = data[orig_key]
860
 
        self.set_data(data)
861
 
    
862
 
    def new_value(self, key, value):
863
 
        """
864
 
        Create new value in data
865
 
        (implemented differently for remote table view)
866
 
        """
867
 
        data = self.model.get_data()
868
 
        data[key] = value
869
 
        self.set_data(data)
870
 
            
871
 
    def refresh_menu(self):
872
 
        """Refresh context menu"""
873
 
        data = self.model.get_data()
874
 
        index = self.currentIndex()
875
 
        condition = (not isinstance(data, tuple)) and index.isValid() \
876
 
                    and not self.readonly
877
 
        self.edit_action.setEnabled( condition )
878
 
        self.remove_action.setEnabled( condition )
879
 
        self.insert_action.setEnabled( not self.readonly )
880
 
        self.refresh_plot_entries(index)
881
 
        
882
 
    def set_filter(self, dictfilter=None):
883
 
        """Set table dict filter"""
884
 
        self.dictfilter = dictfilter
885
 
 
886
867
    def copy(self):
887
868
        """Copy text to clipboard"""
888
869
        clipboard = QApplication.clipboard()
889
 
        data = self.model.get_data()
890
870
        clipl = []
891
871
        for idx in self.selectedIndexes():
892
872
            if not idx.isValid:
893
873
                continue
894
 
            _txt = u''
895
 
            if isinstance(data,dict):
896
 
                _txt = unicode(data.get(self.model.keys[idx.row()]))
897
 
            else:
898
 
                _txt = unicode(data[idx.row()])
899
 
            clipl.append(_txt)
 
874
            clipl.append(unicode(self.delegate.get_value(idx)))
900
875
        clipboard.setText(u'\n'.join(clipl))
901
876
    
902
877
    def import_from_string(self, text, title=None):
903
878
        """Import data from string"""
904
 
#        if isinstance(text, basestring):
905
 
#            text = QString(text)
906
879
        data = self.model.get_data()
907
 
        varname_base = translate("DictEditor", "new")
908
 
        try:
909
 
            varname_base = str(varname_base)
910
 
        except UnicodeEncodeError:
911
 
            varname_base = unicode(varname_base)
912
 
        get_varname = lambda index: varname_base + ("%03d" % index)
913
 
        index = 0
914
 
        while get_varname(index) in data:
915
 
            index += 1
916
880
        editor = ImportWizard(self, text, title=title,
917
881
                              contents_title=translate("DictEditor",
918
882
                                                       "Clipboard contents"),
919
 
                              varname=get_varname(index))
 
883
                              varname=fix_reference_name("data",
 
884
                                                         blacklist=data.keys()))
920
885
        if editor.exec_():
921
886
            var_name, clip_data = editor.get_data()
922
 
            data[var_name] = clip_data
923
 
            self.set_data(data)
 
887
            self.new_value(var_name, clip_data)
924
888
    
925
889
    def paste(self):
926
890
        """Import text/data/code from clipboard"""
937
901
                                translate("DictEditor", "Empty clipboard"),
938
902
                                translate("DictEditor", "Nothing to be imported"
939
903
                                          " from clipboard."))
 
904
        
 
905
 
 
906
class DictEditorTableView(BaseTableView):
 
907
    """DictEditor table view"""
 
908
    def __init__(self, parent, data, readonly=False, title="",
 
909
                 names=False, truncate=True, minmax=False,
 
910
                 inplace=False, collvalue=True):
 
911
        BaseTableView.__init__(self, parent)
 
912
        self.dictfilter = None
 
913
        self.readonly = readonly or isinstance(data, tuple)
 
914
        self.model = None
 
915
        self.delegate = None
 
916
        DictModelClass = ReadOnlyDictModel if self.readonly else DictModel
 
917
        self.model = DictModelClass(self, data, title, names=names,
 
918
                                    truncate=truncate, minmax=minmax,
 
919
                                    collvalue=collvalue)
 
920
        self.setModel(self.model)
 
921
        self.delegate = DictDelegate(self, inplace=inplace)
 
922
        self.setItemDelegate(self.delegate)
 
923
 
 
924
        self.setup_table()
 
925
        self.menu = self.setup_menu(truncate, minmax, inplace, collvalue)
 
926
    
 
927
    def remove_values(self, keys):
 
928
        """
 
929
        Remove values from data
 
930
        (implemented differently for remote table view)
 
931
        """
 
932
        data = self.model.get_data()
 
933
        for key in sorted(keys,reverse=True):
 
934
            data.pop(key)
 
935
            self.set_data(data)
 
936
 
 
937
    def copy_value(self, orig_key, new_key):
 
938
        """
 
939
        Copy value
 
940
        (implemented differently for remote table view)
 
941
        """
 
942
        data = self.model.get_data()
 
943
        data[new_key] = data[orig_key]
 
944
        self.set_data(data)
 
945
    
 
946
    def new_value(self, key, value):
 
947
        """
 
948
        Create new value in data
 
949
        (implemented differently for remote table view)
 
950
        """
 
951
        data = self.model.get_data()
 
952
        data[key] = value
 
953
        self.set_data(data)
 
954
            
 
955
    def refresh_menu(self):
 
956
        """Refresh context menu"""
 
957
        data = self.model.get_data()
 
958
        index = self.currentIndex()
 
959
        condition = (not isinstance(data, tuple)) and index.isValid() \
 
960
                    and not self.readonly
 
961
        self.edit_action.setEnabled( condition )
 
962
        self.remove_action.setEnabled( condition )
 
963
        self.insert_action.setEnabled( not self.readonly )
 
964
        self.refresh_plot_entries(index)
 
965
        
 
966
    def set_filter(self, dictfilter=None):
 
967
        """Set table dict filter"""
 
968
        self.dictfilter = dictfilter
940
969
 
941
970
 
942
971
class DictEditorWidget(QWidget):
965
994
    def __init__(self, data, title="", width=500,
966
995
                 readonly=False, icon='dictedit.png', remote=False):
967
996
        QDialog.__init__(self)
968
 
        import copy
969
 
        self.data_copy = copy.deepcopy(data)
 
997
        if isinstance(data, dict):
 
998
            # dictionnary
 
999
            self.data_copy = data.copy()
 
1000
        else:
 
1001
            # list, tuple
 
1002
            self.data_copy = data[:]
970
1003
        self.widget = DictEditorWidget(self, self.data_copy, title=title,
971
1004
                                       readonly=readonly, remote=remote)
972
1005
        
1012
1045
    (instantiate a new QApplication if necessary,
1013
1046
    so it can be called directly from the interpreter)
1014
1047
    """
1015
 
    if QApplication.startingUp():
1016
 
        QApplication([])
 
1048
    _app = qapplication()
1017
1049
    dialog = DictEditor(seq)
1018
1050
    if dialog.exec_():
1019
1051
        return dialog.get_copy()
1100
1132
    return output_dict
1101
1133
 
1102
1134
 
1103
 
if __name__ == "__main__":
1104
 
    import numpy as np
 
1135
def get_test_data():
 
1136
    """Create test data"""
 
1137
    import numpy as np, PIL.Image
 
1138
    image = PIL.Image.fromarray(np.random.rand(100, 100))
1105
1139
    testdict = {'d': 1, 'a': np.random.rand(10, 10), 'b': [1, 2]}
1106
1140
    testdate = datetime.date(1945, 5, 8)
1107
 
    example = {'str': 'kjkj kj k j j kj k jkj',
1108
 
               'unicode': u'éù',
1109
 
               'list': [1, 3, [4, 5, 6], 'kjkj', None],
1110
 
               'tuple': ([1, testdate, testdict], 'kjkj', None),
1111
 
               'dict': testdict,
1112
 
               'float': 1.2233,
1113
 
               'array': np.random.rand(10, 10),
1114
 
               'empty_array': np.array([]),
1115
 
               'date': testdate,
1116
 
               'datetime': datetime.datetime(1945, 5, 8),
1117
 
               }
1118
 
    
1119
 
#    # Remote dict test:
1120
 
#    from spyderlib.widgets.monitor import make_remote_view
1121
 
#    remote = make_remote_view(example)
1122
 
#    from pprint import pprint
1123
 
#    pprint(remote)
1124
 
#    if QApplication.startingUp():
1125
 
#        QApplication([])
1126
 
#    dialog = DictEditor(remote, remote=True)
1127
 
#    if dialog.exec_():
1128
 
#        print dialog.get_copy()
1129
 
    
1130
 
    out = dedit(example)
 
1141
    return {'str': 'kjkj kj k j j kj k jkj',
 
1142
            'unicode': u'éù',
 
1143
            'list': [1, 3, [4, 5, 6], 'kjkj', None],
 
1144
            'tuple': ([1, testdate, testdict], 'kjkj', None),
 
1145
            'dict': testdict,
 
1146
            'float': 1.2233,
 
1147
            'array': np.random.rand(10, 10),
 
1148
            '1D-array': np.linspace(-10, 10),
 
1149
            'empty_array': np.array([]),
 
1150
            'image': image,
 
1151
            'date': testdate,
 
1152
            'datetime': datetime.datetime(1945, 5, 8),
 
1153
            }
 
1154
 
 
1155
def test():
 
1156
    """Dictionary editor test"""
 
1157
    out = dedit( get_test_data() )
1131
1158
    print "out:", out
1132
 
    
 
 
b'\\ No newline at end of file'
 
1159
    
 
1160
def remote_editor_test():
 
1161
    """Remote dictionary editor test"""
 
1162
    from spyderlib.widgets.externalshell.globalsexplorer import get_settings
 
1163
    from spyderlib.widgets.externalshell.monitor import make_remote_view
 
1164
    remote = make_remote_view(get_test_data(), get_settings())
 
1165
    from pprint import pprint
 
1166
    pprint(remote)
 
1167
    _app = qapplication()
 
1168
    dialog = DictEditor(remote, remote=True)
 
1169
    if dialog.exec_():
 
1170
        print dialog.get_copy()
 
1171
 
 
1172
if __name__ == "__main__":
 
1173
    test()